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));
|
|
/// <summary>
|
/// 获取需要渲染的属性
|
/// </summary>
|
/// <param name="obj"></param>
|
/// <returns></returns>
|
public static Dictionary<string, PropertyInfo> GetRenderProperty(object obj)
|
{
|
var res = new Dictionary<string, PropertyInfo>();
|
var properties = obj.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
|
foreach (var property in properties)
|
{
|
if (property.GetCustomAttribute<DisplayAttribute>() != null)
|
{
|
res[property.Name] = property;
|
}
|
}
|
return res;
|
}
|
|
/// <summary>
|
/// 获取需要渲染的方法
|
/// </summary>
|
/// <param name="obj"></param>
|
/// <returns></returns>
|
public static Dictionary<string, MethodInfo> GetRenderMethods(object obj)
|
{
|
var res = new Dictionary<string, MethodInfo>();
|
var methods = obj.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public);
|
foreach (var method in methods)
|
{
|
if (method.GetCustomAttribute<DisplayAttribute>() != 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<FilePathAttribute>() 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<FilePathAttribute>() 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<DynamicSelectAttribute>() 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<BindingListAttribute>() 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<DisplayAttribute>() 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<TreeDataAttribute>() 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<IgnoreVariable>() == 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<BrowsableAttribute>() is BrowsableAttribute attr)
|
return attr.Browsable;
|
if (member.HasAttribute<OutputAttribute>())
|
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<DisplayAttribute>();
|
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<DependOnAttribute>() 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<DisplayAttribute>();
|
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;
|
}
|
}
|
}
|