您可以利用TypeDescriptor 服务来扩展具有计算属性的模型类。
为此,您需要一些辅助类。
首先,自定义计算属性的通用类:
public class CalculatedProperty<TComponent, TValue> : PropertyDescriptor
{
private Func<TComponent, TValue> func;
public CalculatedProperty(string name, Func<TComponent, TValue> func)
: base(name, null)
{
this.func = func;
}
public override Type ComponentType { get { return typeof(TComponent); } }
public override bool IsReadOnly { get { return true; } }
public override Type PropertyType { get { return typeof(TValue); } }
public override bool CanResetValue(object component) { return false; }
public override object GetValue(object component) { return func((TComponent)component); }
public override void SetValue(object component, object value) { throw new InvalidOperationException(); }
public override bool ShouldSerializeValue(object component) { return false; }
public override void ResetValue(object component) { throw new InvalidOperationException(); }
}
和一个工厂(使其更易于使用):
public static class CalculatedProperty
{
public static PropertyDescriptor Create<TComponent, TValue>(string name, Func<TComponent, TValue> func)
{
return new CalculatedProperty<TComponent, TValue>(name, func);
}
}
接下来,为了向现有类“添加”属性,您需要一个实现ICustomTypeDescriptor 接口并通过自定义TypeDescriptionProvider 公开它的类。这个过程有点复杂,所以我封装在下面的类中:
public class CustomPropertyTypeDescriptor : CustomTypeDescriptor
{
public static void Register(Type type, params PropertyDescriptor[] customProperties)
{
var baseProvider = TypeDescriptor.GetProvider(type);
var typeDescriptor = new CustomPropertyTypeDescriptor(baseProvider.GetTypeDescriptor(type), customProperties);
TypeDescriptor.AddProvider(new Provider(baseProvider, typeDescriptor), type);
}
PropertyDescriptor[] customProperties;
private CustomPropertyTypeDescriptor(ICustomTypeDescriptor baseDescriptor, PropertyDescriptor[] customProperties)
: base(baseDescriptor)
{
this.customProperties = customProperties;
}
public override PropertyDescriptorCollection GetProperties() { return GetProperties(null); }
public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
{
return new PropertyDescriptorCollection(base.GetProperties(attributes).Cast<PropertyDescriptor>().Concat(customProperties).ToArray());
}
private class Provider : TypeDescriptionProvider
{
private CustomPropertyTypeDescriptor typeDescriptor;
public Provider(TypeDescriptionProvider baseProvider, CustomPropertyTypeDescriptor typeDescriptor)
: base(baseProvider)
{
this.typeDescriptor = typeDescriptor;
}
public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
{
return typeDescriptor;
}
}
}
这就是通用部分的全部内容。最后,您只需在应用程序启动时为每个需要计算属性的类调用一次CustomPropertyTypeDescriptor.Register,并使用CalculatedProperty.Create 方法提供它们。
这是一个例子:
型号:(注意没有Total属性)
public class OrderLine
{
public string ItemNo { get; set; }
(many other properties here...)
public int Quantity { get; set; }
public decimal Price { get; set; }
}
应用:
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
CustomPropertyTypeDescriptor.Register(typeof(OrderLine),
CalculatedProperty.Create("Total", (OrderLine source) => source.Quantity * source.Price)
);
var form = new Form();
var dg = new DataGridView { Dock = DockStyle.Fill, Parent = form };
dg.DataSource = Enumerable.Range(1, 10).Select(n => new OrderLine
{
ItemNo = "Item#" + n,
Quantity = n,
Price = 10 * n
}).ToList();
Application.Run(form);
}
}
结果:(注意Total 列)