我所拥有的是一个没有“命名”属性的类:
public class ColumnsValues
{
public int IdProperty { get; set; }
public string ColumnName { get; set; }
public string ValueOfColumn { get; set; }
public TypeCode TypeOfColumn { get; set; }
}
并且数据存储在“ObservableCollection coll”中(例如,对于 Person ): 关于大学的另一个例子:
我的目标是使用DataGrid
创建DataTemplates
。为了实现我的目标,我使用DataTable
,我可以在其中定义类型:
MyDataTable.Columns.Add("I am bool", typeof(bool));
以及DataTemplates
的{{1}}示例:
DataGrid
是否有更好的方法(不是DataTable或改进此方法)将我的类ColumnsValues绑定到DataGrid而不会牺牲使用DataTemplates作为值类型?
我知道这个问题有很多机会被关闭,但我想尝试询问潜在的经历。任何帮助将不胜感激!
答案 0 :(得分:1)
详细说明我的评论,这里有一些粗略的示例代码来说明这个想法:
class DynamicPerson : ICustomTypeDescriptor
{
public ObservableCollection<ColumnsValues> Features { get; } = new ObservableCollection<ColumnsValues>();
#region ICustomTypeDescriptor
private CustomTypeDescriptor _customTypeDescriptor = new DynamicPersonTypeDescriptor();
public String GetClassName() => _customTypeDescriptor.GetClassName();
public AttributeCollection GetAttributes() => _customTypeDescriptor.GetAttributes();
public String GetComponentName() => _customTypeDescriptor.GetComponentName();
public TypeConverter GetConverter() => _customTypeDescriptor.GetConverter();
public EventDescriptor GetDefaultEvent() => _customTypeDescriptor.GetDefaultEvent();
public PropertyDescriptor GetDefaultProperty() => _customTypeDescriptor.GetDefaultProperty();
public object GetEditor(Type editorBaseType) => _customTypeDescriptor.GetEditor(editorBaseType);
public EventDescriptorCollection GetEvents(Attribute[] attributes) => _customTypeDescriptor.GetEvents(attributes);
public EventDescriptorCollection GetEvents() => _customTypeDescriptor.GetEvents();
public object GetPropertyOwner(PropertyDescriptor pd) => this;
public PropertyDescriptorCollection GetProperties(Attribute[] attributes) => GetProperties();
public PropertyDescriptorCollection GetProperties()
{
var collectionDescriptors = Features.Select(x => new DynamicPersonPropertyDescriptor(Features, x)).ToArray();
return new PropertyDescriptorCollection(collectionDescriptors);
}
#endregion
class DynamicPersonTypeDescriptor : CustomTypeDescriptor
{ }
class DynamicPersonPropertyDescriptor : PropertyDescriptor
{
TypeConverter typeConverter;
Collection<ColumnsValues> features;
ColumnsValues feature;
public DynamicPersonPropertyDescriptor(Collection<ColumnsValues> features, ColumnsValues feature)
: base(feature.ColumnName, new Attribute[] { new BindableAttribute(true) })
{
this.features = features;
this.feature = feature;
typeConverter = TypeDescriptor.GetConverter(feature.Type);
}
public override Type ComponentType => feature.Type;
public override bool IsReadOnly => false;
public override Type PropertyType => feature.Type;
public override bool CanResetValue(object component) => true;
public override object GetValue(object component) => typeConverter.ConvertFrom(feature.ValueOfColumn);
public override void ResetValue(object component)
{
feature.ValueOfColumn = null;
}
public override void SetValue(object component, object value)
{
feature.ValueOfColumn = Convert.ToString(value);
}
public override bool ShouldSerializeValue(object component) => true;
}
public class ColumnsValues
{
public int IdProperty { get; set; }
public string ColumnName { get; set; }
public string ValueOfColumn { get; set; }
public TypeCode TypeOfColumn { get; set; }
public Type Type => Type.GetType("System." + TypeOfColumn);
}
}
请注意,您原则上可以从抽象类DynamicPerson
派生CustomTypeDescriptor
,尽管这可能是糟糕的设计。
这将像这样使用
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var staff = new List<DynamicPerson>();
var person1 = new DynamicPerson();
var feature1 = new DynamicPerson.ColumnsValues
{
ColumnName = "FirstName",
IdProperty = 1,
TypeOfColumn = TypeCode.String,
ValueOfColumn = "Albert"
};
person1.Features.Add(feature1);
var feature2 = new DynamicPerson.ColumnsValues
{
ColumnName = "LastName",
IdProperty = 1,
TypeOfColumn = TypeCode.String,
ValueOfColumn = "Dunno"
};
person1.Features.Add(feature2);
var feature3 = new DynamicPerson.ColumnsValues
{
ColumnName = "Alive",
IdProperty = 1,
TypeOfColumn = TypeCode.Boolean,
ValueOfColumn = "True"
};
person1.Features.Add(feature3);
staff.Add(person1);
staff.Add(person1);
DataContext = staff;
}
}
XAML部分:
<DataGrid Name="Persons" ItemsSource="{Binding}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="First name" Binding="{Binding FirstName}"/>
<DataGridTextColumn Header="Last name" Binding="{Binding LastName}"/>
<DataGridCheckBoxColumn Header="Alive" Binding="{Binding Alive}"/>
</DataGrid.Columns>
</DataGrid>
如果您想使用AutoGenerateColumns="True"
自动生成列,DynamicPerson还需要使用[TypeDescriptionProvider(typeof(DynamicPersonDescriptionProvider))]
属性进行装饰。为此,您需要定义一个派生自DynamicPersonDescriptionProvider
的附加类TypeDescriptionProvider
并覆盖GetTypeDescriptor方法。