需求/问题:
INotifyPropertyChanged
的实体作为DataSource
时,每个更改通知刷新绑定到该数据源的所有控件(易于验证 - 只需绑定两个属性对于两个控件并在其中一个上调用更改通知,您将看到两个属性都被命中并重新评估。)IDataErrorInfo
)。 (可能使用ErrorProvider
)将实体用作控件的DataSource
会导致性能问题,并且当控件只能读取时,会使生活变得更加困难。
我想过创建一种包含实体和特定属性的包装器,以便每个控件都绑定到不同的DataSource
。此外,该包装器可以保存该属性的ReadOnly
指示符,因此控件将直接绑定到该值。
包装器可能如下所示:
interface IPropertyWrapper : INotifyPropertyChanged, IDataErrorInfo
{
object Value { get; set; }
bool IsReadOnly { get; }
}
但这对每个属性(属性包装器)
也意味着不同的ErrorProvider
我觉得我正在尝试重新发明轮子......处理这些复杂的绑定需求的“正确”方法是什么?
非常感谢。
答案 0 :(得分:3)
您可以为实现ICustomTypeDescriptor
的实体编写包装器。这样,您可以决定哪些属性是只读的......但对于不太复杂的情况,这是非常多的工作。
当您希望该属性为只读时,更简单的解决方案是将绑定的DataSourceUpdateMode
更改为Never
。
更新:这是实现ICustomTypeDescriptor
的基本包装器:
class EntityWrapper<T> : CustomTypeDescriptor
{
public EntityWrapper(T entity)
{
this.Entity = entity;
var properties = TypeDescriptor.GetProperties(typeof(T))
.Cast<PropertyDescriptor>()
.ToArray();
ReadOnly = properties.ToDictionary(p => p.Name, p => p.IsReadOnly);
_properties = new PropertyDescriptorCollection(properties
.Select(p => new WrapperPropertyDescriptor(p, this))
.ToArray());
}
public T Entity { get; private set; }
public Dictionary<string, bool> ReadOnly { get; private set; }
public override PropertyDescriptorCollection GetProperties()
{
return _properties;
}
public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
{
return _properties;
}
private PropertyDescriptorCollection _properties;
private class WrapperPropertyDescriptor : PropertyDescriptor
{
private EntityWrapper<T> _entityWrapper;
private PropertyDescriptor _property;
public WrapperPropertyDescriptor(PropertyDescriptor property, EntityWrapper<T> entityWrapper)
: base(property)
{
_property = property;
_entityWrapper = entityWrapper;
}
public override bool CanResetValue(object component)
{
return _property.CanResetValue(component);
}
public override Type ComponentType
{
get { return _property.ComponentType; }
}
public override object GetValue(object component)
{
return _property.GetValue(component);
}
public override bool IsReadOnly
{
get
{
return _entityWrapper.ReadOnly[this.Name];
}
}
public override Type PropertyType
{
get { return _property.PropertyType; }
}
public override void ResetValue(object component)
{
_property.ResetValue(component);
}
public override void SetValue(object component, object value)
{
_property.SetValue(component, value);
}
public override bool ShouldSerializeValue(object component)
{
return _property.ShouldSerializeValue(component);
}
}
}
正如您所看到的,完全可以将属性设置为只读一个实例:
MyEntity a = new MyEntity { Foo = "hello", Bar = 42 };
MyEntity b = new MyEntity { Foo = "world", Bar = 5 };
EntityWrapper<MyEntity> wa = new EntityWrapper<MyEntity>(a);
EntityWrapper<MyEntity> wb = new EntityWrapper<MyEntity>(b);
var fooA = wa.GetProperties()["Foo"];
var fooB = wb.GetProperties()["Foo"];
wa.ReadOnly["Foo"] = false;
wb.ReadOnly["Foo"] = true;
Console.WriteLine("Property Foo of object a is read-only : {0}", fooA.IsReadOnly);
Console.WriteLine("Property Foo of object b is read-only : {0}", fooB.IsReadOnly);
答案 1 :(得分:0)
我不会单独包装每个属性...我会包装根域对象。在那里,我将实现readonly逻辑...并且只在readonly标志设置为false时才在真实域objet上设置值。