我在应用程序中实现了ICustomTypeDescriptor,以便能够在运行时定义自定义属性。我的基本实现如下:
public class DynamicClass <T> : ICustomTypeDescriptor
{
private readonly T _object;
public DynamicClass(T trackedObject)
{
_object = trackedObject;
}
// Collection to code add dynamic properties
public KeyedCollection<string, DynamicProperty> Properties
{
get;
private set;
}
// ICustomTypeDescriptor implementation
public AttributeCollection GetAttributes()
{
return TypeDescriptor.GetAttributes(_object, true);
}
public string GetClassName()
{
return TypeDescriptor.GetClassName(_object, true);
}
public string GetComponentName()
{
return TypeDescriptor.GetComponentName(_object, true);
}
public TypeConverter GetConverter()
{
return TypeDescriptor.GetConverter(_object, true);
}
public EventDescriptor GetDefaultEvent()
{
return TypeDescriptor.GetDefaultEvent(_object, true);
}
public PropertyDescriptor GetDefaultProperty()
{
return TypeDescriptor.GetDefaultProperty(_object, true);
}
public object GetEditor(Type editorBaseType)
{
throw new NotImplementedException();
}
public EventDescriptorCollection GetEvents()
{
return TypeDescriptor.GetEvents(_object, true);
}
public EventDescriptorCollection GetEvents(Attribute[] attributes)
{
return TypeDescriptor.GetEvents(_object, attributes, true);
}
PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
{
return TypeDescriptor.GetProperties(_object, true);
}
public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
{
return TypeDescriptor.GetProperties(_object, attributes, true);
}
public object GetPropertyOwner(PropertyDescriptor pd)
{
return _object;
}
}问题是,现在当我使用DynamicClass绑定将对象绑定到文本框时,它不再工作了。
我就是这样用的:
DynamicClass<ExtensionModel> binder = new DynamicClass<ExtensionModel>(ext);
_versionLabel.DataBindings.Add("Text", binder, "SelectedVersion", false, DataSourceUpdateMode.OnPropertyChanged);我得到了一个例外:“Object与目标类型不匹配。”
对象与目标类型不匹配。
(在System.Reflection.RuntimeMethodInfo.CheckConsistency(Object目标)在System.Reflection.RuntimeMethodInfo.Invoke(Object obj,BindingFlags invokeAttr,binder粘合剂,Object[]参数,CultureInfo文化,布尔skipVisibilityChecks)在System.Reflection.RuntimeMethodInfo.Invoke(Object obj,BindingFlags invokeAttr,binder粘合剂,Object[]参数,CultureInfo培养)
在System.ComponentModel.ReflectEventDescriptor.AddEventHandler(Object组件上,代表值在System.ComponentModel.ReflectPropertyDescriptor.AddValueChanged(Object组件上,EventHandler处理程序在System.Windows.Forms.BindToObject.CheckBinding() at System.Windows.Forms.Binding.SetListManager(BindingManagerBase bindingManagerBase(在System.Windows.Forms.ListManagerBindingsCollection.AddCore(Binding dataBinding)在System.Windows.Forms.BindingsCollection.Add(Binding绑定时)在System.Windows.Forms.BindingContext.UpdateBinding(BindingContext newBindingContext,绑定)在System.Windows.Forms.Control.UpdateBindings()
如果我使用ext对象而不是绑定器,则绑定可以工作。我在ICustomTypeDescriptor实现中遗漏了什么吗?
发布于 2013-12-25 18:27:59
您必须用自定义描述符包装原始描述符。以下是代码:
#region IBindingProxy
public interface IBindingProxy
{
void CheckAndNotify();
}
#endregion
public class BindingProxy : CustomTypeDescriptor, INotifyPropertyChanged, IBindingProxy
{
#region Static Constructor
private static readonly IDictionary<Type, PropertyDescriptorCollection> propertyCache;
static BindingProxy()
{
propertyCache = new Dictionary<Type, PropertyDescriptorCollection>();
}
private static PropertyDescriptorCollection GetTypeProperties(Type type)
{
lock (propertyCache)
{
PropertyDescriptorCollection properties;
if (!propertyCache.TryGetValue(type, out properties))
{
var list = new List<PropertyDescriptor>();
GetTypeProperties(list, type);
properties = new PropertyDescriptorCollection(list.ToArray());
propertyCache.Add(type, properties);
}
return properties;
}
}
private static void GetTypeProperties(ICollection<PropertyDescriptor> list, Type type)
{
foreach (var @interface in type.GetInterfaces())
{
GetTypeProperties(list, @interface);
}
foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(type))
{
list.Add(new ProxyPropertyDescriptor(property));
}
}
#endregion
private readonly PropertyDescriptorCollection properties;
private readonly object instance;
public event PropertyChangedEventHandler PropertyChanged;
public BindingProxy(object instance)
{
this.instance = instance;
properties = instance == null
? PropertyDescriptorCollection .Empty
: GetTypeProperties(instance.GetType());
}
public void CheckAndNotify()
{
OnPropertyChanged(null);
}
protected virtual void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
public object Instance
{
get { return instance; }
}
public override PropertyDescriptorCollection GetProperties()
{
return GetProperties(null);
}
public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
{
return properties;
}
public override Object GetPropertyOwner(PropertyDescriptor property)
{
return this;
}
#region ProxyPropertyDescriptor
private class ProxyPropertyDescriptor : PropertyDescriptor
{
private readonly PropertyDescriptor property;
public ProxyPropertyDescriptor(PropertyDescriptor property) : base(property)
{
this.property = property;
}
//public override string DisplayName
//{
// get { return property.DisplayName; }
//}
//public override string Description
//{
// get { return property.Description; }
//}
//public override string Category
//{
// get { return property.Category; }
//}
//public override TypeConverter Converter
//{
// get { return converter; }
//}
public override bool IsReadOnly
{
get { return property.IsReadOnly; }
}
public override void ResetValue(object component)
{
}
public override bool CanResetValue(object component)
{
return false;
}
public override bool ShouldSerializeValue(object component)
{
return false;
}
public override Type ComponentType
{
get { return property.ComponentType; }
}
public override Type PropertyType
{
get { return property.PropertyType; }
}
public override object GetValue(object component)
{
return property.GetValue(((BindingProxy)component).instance);
}
public override void SetValue(object component, object value)
{
var instance = ((BindingProxy)component).instance;
property.SetValue(instance, value);
OnValueChanged(instance, EventArgs.Empty);
}
}
#endregion
}发布于 2012-06-09 09:36:13
我已经在我的测试代码中复制了您的问题。我可以看到,如果您不在INotifyPropertyChanged上实现ExtensionModel,那么它就能工作!
因此,ICustomTypeDescriptor的实现有一些不适用于实现INotifyPropertyChanged的属性类的东西。
这是可行的,但是如果取消对INotifyPropertyChange的注释,它就会崩溃。
public class BindingExample
{
public void Shows_Binding_To_A_Label_With_DynamicClass()
{
Form frm = new Form();
Label _versionLabel = new Label();
frm.Controls.Add(_versionLabel);
ExtensionModel ext = new ExtensionModel() { SelectedVersion = "DynamicClass Example" };
DynamicClass<ExtensionModel> binder = new DynamicClass<ExtensionModel>(ext);
_versionLabel.DataBindings.Add("Text", binder, "SelectedVersion", false, DataSourceUpdateMode.OnPropertyChanged);
frm.ShowDialog();
}
}
public class ExtensionModel// : INotifyPropertyChanged
{
string selectedVersion;
public string SelectedVersion
{
get { return selectedVersion; }
set
{
selectedVersion = value;
onPropertyChanged("SelectedVersion");
}
}
void onPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}我想让这一切顺利进行,所以我会继续玩下去。
https://stackoverflow.com/questions/9427587
复制相似问题