using OpenTap;
|
using OpenTap.Addin.Annotation;
|
using OpenTapEditor.UI;
|
using System.ComponentModel;
|
using System.Reflection;
|
using System.Windows;
|
using System.Windows.Controls;
|
using System.Windows.Data;
|
using System.Xml.Serialization;
|
|
namespace OpenTapEditor.Provider
|
{
|
public class GridControlProvider
|
{
|
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;
|
}
|
|
private static FrameworkElement RanderElement(object source, PropertyInfo property)
|
{
|
if (property.GetCustomAttribute<FilePathAttribute>() is FilePathAttribute fpa)
|
{
|
FileSelector fs = new FileSelector() { Mode = fpa.Mode, Ext = fpa.FileExtension };
|
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();
|
|
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.TextProperty, new Binding(property.Name)
|
{
|
Source = source,
|
Mode = BindingMode.TwoWay
|
});
|
}
|
return combox;
|
}
|
|
if (property.GetCustomAttribute<BindingListAttribute>() is BindingListAttribute bla)
|
{
|
var dataGrid = new DataGrid()
|
{
|
MinHeight = 100,
|
HorizontalScrollBarVisibility = ScrollBarVisibility.Disabled
|
};
|
|
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)
|
{
|
DataGridHelper.SetDataGridColumns(dataGrid, propertyType.GetGenericArguments()[0]);
|
}
|
else
|
{
|
DataGridHelper.SetDataGridColumns(dataGrid, propertyType);
|
}
|
return dataGrid;
|
}
|
|
if (property.PropertyType == typeof(bool?) || property.PropertyType == typeof(bool))
|
{
|
CheckBox cb = new CheckBox();
|
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();
|
combox.VerticalAlignment = VerticalAlignment.Center;
|
combox.ItemsSource = 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 };
|
|
BindingOperations.SetBinding(tree, VariableTree.DatasourceProperty,
|
new Binding(property.Name)
|
{
|
Source = source,
|
Mode = BindingMode.TwoWay
|
});
|
return tree;
|
}
|
|
if (property.GetCustomAttribute<IgnoreVariable>() is IgnoreVariable iv)
|
{
|
TextBox tb = new TextBox
|
{
|
IsReadOnly = !(property.CanWrite && property.SetMethod?.IsPublic == true)
|
};
|
BindingOperations.SetBinding(tb, TextBox.TextProperty,
|
new Binding(property.Name)
|
{
|
Source = source,
|
Mode = tb.IsReadOnly ? BindingMode.OneWay : BindingMode.TwoWay,
|
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
|
});
|
return tb;
|
}
|
|
VariableTextBox vtb = new VariableTextBox() { Step = (ITestStep)source };
|
BindingOperations.SetBinding(vtb, VariableTextBox.ValueProperty,
|
new Binding(property.Name)
|
{
|
Source = source,
|
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
|
});
|
|
return vtb;
|
}
|
|
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)
|
{
|
var grid = new Grid()
|
{
|
|
};
|
grid.ColumnDefinitions.Add(new ColumnDefinition()
|
{
|
Width = new GridLength(1, GridUnitType.Auto)
|
});
|
grid.ColumnDefinitions.Add(new ColumnDefinition()
|
{
|
Width = new GridLength(1, GridUnitType.Star)
|
});
|
|
var properties = GetRenderProperty(obj);
|
|
int i = 0;
|
foreach (var key in properties.Keys)
|
{
|
|
var property = properties[key];
|
var display = property.GetCustomAttribute<DisplayAttribute>();
|
var label = new Label
|
{
|
Content = display.Name
|
};
|
|
grid.RowDefinitions.Add(new RowDefinition()
|
{
|
Height = new GridLength(1, GridUnitType.Auto)
|
});
|
|
grid.Children.Add(label);
|
Grid.SetRow(label, i);
|
Grid.SetColumn(label, 0);
|
|
var element = RanderElement(obj, property);
|
if (element != null)
|
{
|
grid.Children.Add(element);
|
Grid.SetRow(element, i);
|
Grid.SetColumn(element, 1);
|
}
|
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);
|
Grid.SetColumnSpan(btn, 2);
|
i++;
|
}
|
|
if (obj is ITestStepParent tsp)
|
{
|
grid.RowDefinitions.Add(new RowDefinition()
|
{
|
Height = new GridLength(1, GridUnitType.Auto)
|
});
|
|
var label = new Label
|
{
|
Content = "Break Condition"
|
};
|
grid.Children.Add(label);
|
Grid.SetRow(label, i);
|
Grid.SetColumn(label, 0);
|
|
var s = BreakConditionProperty.GetBreakCondition(tsp);
|
var element = new BreakConditionCtrl
|
{
|
Source = tsp
|
};
|
if (element != null)
|
{
|
grid.Children.Add(element);
|
Grid.SetRow(element, i);
|
Grid.SetColumn(element, 1);
|
}
|
}
|
return grid;
|
}
|
}
|
}
|