using OpenTap; using OpenTap.Addin.Annotation; using OpenTap.Addin.Util; using OpenTapEditor.Entity; using OpenTapEditor.UI; using Panuon.WPF.UI; using System.ComponentModel; using System.Reflection; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Media; using System.Xml.Serialization; using UILib.DpUtil; namespace OpenTapEditor.Provider { public class FormGroupProvider { private static ITypeData resourceTypeData = TypeData.FromType(typeof(IResource)); /// /// 获取需要渲染的属性 /// /// /// public static Dictionary GetRenderProperty(object obj) { var res = new Dictionary(); var properties = obj.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public); foreach (var property in properties) { if (property.GetCustomAttribute() != null) { res[property.Name] = property; } } return res; } /// /// 获取需要渲染的方法 /// /// /// public static Dictionary GetRenderMethods(object obj) { var res = new Dictionary(); var methods = obj.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public); foreach (var method in methods) { if (method.GetCustomAttribute() != null) { res[method.Name] = method; } } return res; } public static FrameworkElement RanderElement(object source, DisplayAttribute display, PropertyInfo property) { Thickness margin = new Thickness(5, 0, 0, 0); TestStep step = source as TestStep; if (property.GetCustomAttribute() is FilePathAttribute lfpa && property.PropertyType == typeof(LocationString)) { //LocationString lls = (LocationString)property.GetValue(source); //LocationSelector ls = new LocationSelector() { Mode = lfpa.Mode, Filter = lfpa.FileExtension, IsFolder = lfpa.IsFolder, Margin = margin }; //ls.Plan = step.Root; //BindingOperations.SetBinding(ls, LocationSelector.RelativeProperty, //new Binding(nameof(LocationString.RelativeLocation)) //{ // Source = lls, // Mode = BindingMode.TwoWay, // NotifyOnSourceUpdated = true //}); LocationString lls = (LocationString)property.GetValue(source); LocationSelector ls = new LocationSelector() { Mode = lfpa.Mode, Filter = lfpa.FileExtension, IsFolder = lfpa.IsFolder, Margin = margin }; ls.Plan = step.Root; ls.Location = lls; BindingOperations.SetBinding(ls, LocationSelector.RelativeProperty, new Binding(nameof(LocationString.RelativeLocation)) { Source = lls, Mode = BindingMode.TwoWay, NotifyOnSourceUpdated = true }); BindingOperations.SetBinding(ls, LocationSelector.AbsoluteProperty, new Binding(nameof(LocationString.AbsoluteLocation)) { Source = lls, Mode = BindingMode.TwoWay, NotifyOnSourceUpdated = true }); return ls; } if (property.GetCustomAttribute() is FilePathAttribute fpa) { FileSelector fs = new FileSelector() { Mode = fpa.Mode, Ext = fpa.FileExtension, IsFolder = fpa.IsFolder, Margin = margin }; if (property.PropertyType == typeof(MacroString)) { BindingOperations.SetBinding(fs, FileSelector.FilePathProperty, new Binding(property.Name) { Source = source, Converter = MacroStringConverter.Instance, ConverterParameter = source, Mode = BindingMode.TwoWay, NotifyOnSourceUpdated = true }); } else { BindingOperations.SetBinding(fs, FileSelector.FilePathProperty, new Binding(property.Name) { Source = source, Mode = BindingMode.TwoWay, NotifyOnSourceUpdated = true }); } return fs; } if (property.GetCustomAttribute() is DynamicSelectAttribute dsa) { ComboBox combox = new ComboBox() { Margin = margin }; if (!string.IsNullOrEmpty(dsa.SourceName)) { BindingOperations.SetBinding(combox, ComboBox.ItemsSourceProperty, new Binding(dsa.SourceName) { Source = source, Mode = BindingMode.OneWay }); } if (!string.IsNullOrEmpty(dsa.DisplayName)) { combox.DisplayMemberPath = dsa.DisplayName; combox.SelectedValuePath = dsa.BindingName; BindingOperations.SetBinding(combox, ComboBox.SelectedValueProperty, new Binding(property.Name) { Source = source, Mode = BindingMode.TwoWay }); } else { BindingOperations.SetBinding(combox, ComboBox.SelectedValueProperty, new Binding(property.Name) { Source = source, Mode = BindingMode.TwoWay }); } return combox; } if (property.GetCustomAttribute() is BindingListAttribute bla) { var dataGrid = new DataGrid() { MinHeight = 100, Margin = margin }; // 继承 App 级别的所有资源 dataGrid.Resources.MergedDictionaries.Add(Application.Current.Resources); BindingOperations.SetBinding(dataGrid, DataGrid.ItemsSourceProperty, new Binding(bla.BindingName) { Source = source, Mode = BindingMode.TwoWay, }); dataGrid.CanUserAddRows = bla.CanAdd; dataGrid.AutoGenerateColumns = false; dataGrid.CanUserSortColumns = false; Type propertyType = source?.GetType()?.GetProperty(bla.BindingName)?.PropertyType; if (propertyType?.IsGenericType == true) { OpenTapEditor.UI.DataGridHelper.SetDataGridColumns(dataGrid, propertyType.GetGenericArguments()[0]); } else { OpenTapEditor.UI.DataGridHelper.SetDataGridColumns(dataGrid, propertyType); } return dataGrid; } if (property.PropertyType == typeof(bool?) || property.PropertyType == typeof(bool)) { CheckBox cb = new CheckBox() { Margin = margin }; cb.VerticalAlignment = VerticalAlignment.Center; BindingOperations.SetBinding(cb, CheckBox.IsCheckedProperty, new Binding(property.Name) { Source = source, Mode = BindingMode.TwoWay, }); return cb; } // 枚举 if (property.PropertyType.IsEnum) { ComboBox combox = new ComboBox() { Margin = margin }; if (property.PropertyType.GetCustomAttribute() is DisplayAttribute daa) { var list = EnumData.GetFromEnum(Enum.GetValues(property.PropertyType)); combox.DisplayMemberPath = "Name"; combox.SelectedValuePath = "Value"; combox.ItemsSource = list; BindingOperations.SetBinding(combox, ComboBox.SelectedValueProperty, new Binding(property.Name) { Source = source, Mode = BindingMode.TwoWay }); } else { combox.ItemsSource = Enum.GetValues(property.PropertyType);//System.Enum.GetNames(property.PropertyType); BindingOperations.SetBinding(combox, ComboBox.SelectedItemProperty, new Binding(property.Name) { Source = source, Mode = BindingMode.TwoWay }); } return combox; } /// 参数 if (property.GetCustomAttribute() is TreeDataAttribute tda) { VariableTree tree = new VariableTree() { MinHeight = 100, Margin = margin }; BindingOperations.SetBinding(tree, VariableTree.DatasourceProperty, new Binding(property.Name) { Source = source, Mode = BindingMode.TwoWay }); return tree; } if (source is ITestStep testStep && property.GetCustomAttribute() == null) { VariableTextBox vtb = new VariableTextBox() { Step = testStep, Margin = margin }; BindingOperations.SetBinding(vtb, VariableTextBox.ValueProperty, new Binding(property.Name) { Source = source, Mode = BindingMode.TwoWay, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged }); return vtb; } TextBox tb = new TextBox { IsReadOnly = display.ReadOnly || !(property.CanWrite && property.SetMethod?.IsPublic == true), Margin = margin }; BindingOperations.SetBinding(tb, TextBox.TextProperty, new Binding(property.Name) { Source = source, Mode = tb.IsReadOnly ? BindingMode.OneWay : BindingMode.TwoWay, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged }); return tb; } public static bool FilterMember(IMemberData member) { if (member.DeclaringType.DescendsTo(resourceTypeData) && member.Name == nameof(Resource.Name)) return true; if (member.GetAttribute() is BrowsableAttribute attr) return attr.Browsable; if (member.HasAttribute()) return true; return member.Attributes.Any(a => a is XmlIgnoreAttribute) == false && member.Writable; } public static Grid GetControl(object obj, StepSettingView parent) { var grid = new Grid() { }; // 继承 App 级别的所有资源 grid.Resources.MergedDictionaries.Add(Application.Current.Resources); var properties = GetRenderProperty(obj); int i = 0; string GroupName = new Guid().ToString(); foreach (var key in properties.Keys) { var property = properties[key]; var display = property.GetCustomAttribute(); if (display.Header == ConstNames.CommonHeader) { continue; } var fg = new FormGroup { Orientation = Orientation.Horizontal, GroupName = GroupName, VerticalHeaderAlignment = VerticalAlignment.Top }; fg.SetValue(FormGroup.HeaderProperty, new DynamicResourceExtension(display.Name).ProvideValue(null)); grid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1, GridUnitType.Auto) }); grid.Children.Add(fg); Grid.SetRow(fg, i); FrameworkElement element = RanderElement(obj, display, property); if (element is VariableTextBox vtb) { BindingOperations.SetBinding(vtb, VariableTextBox.SeqProperty, new Binding("Seq") { Source = parent, }); } fg.Content = element; BindingOperations.SetBinding(fg, FormGroup.IsEnabledProperty, new Binding(nameof(StepSettingView.CanEdit)) { Source = parent, }); if (property.GetCustomAttribute() is DependOnAttribute doa) { BindingOperations.SetBinding(fg, FrameworkElement.VisibilityProperty, new Binding(doa.BindingName) { Source = obj, Converter = VisibilityConvertor.Instance, ConverterParameter = doa.TargetValue }); } i++; } foreach (var node in GetRenderMethods(obj)) { var method = node.Value; var display = method.GetCustomAttribute(); var btn = new Button { Content = display.Name }; btn.Click += (sender, e) => { method.Invoke(obj, null); }; grid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1, GridUnitType.Auto) }); grid.Children.Add(btn); Grid.SetRow(btn, i); Grid.SetColumn(btn, 0); i++; } //if (obj is ITestStepParent tsp) //{ // grid.RowDefinitions.Add(new RowDefinition() // { // Height = new GridLength(1, GridUnitType.Auto) // }); // var fg = new FormGroup // { // Orientation = Orientation.Horizontal, // Header = "Break Condition", // GroupName = GroupName // }; // grid.Children.Add(fg); // Grid.SetRow(fg, i); // var s = BreakConditionProperty.GetBreakCondition(tsp); // var element = new BreakConditionCtrl // { // Source = tsp // }; // fg.Content = element; //} GridHelper.SetSpace(grid, 5); GridHelper.RefreshGridSpace(grid); return grid; } } }