我正在尝试使用[TypeDescriptionProviderAttribute],以便为类提供一个自定义类型描述符。这是可行的,但是当我实现INotifyPropertyChanged时,WPF似乎忽略了自定义类型描述符,直接查找CLR属性(如果存在的话)。下面是一个片段,稍后我将粘贴完整的示例:
//[TypeDescriptionProvider(typeof(MyProvider))]
class MyModel : Object
//, INotifyPropertyChanged
//, ICustomTypeDescriptor
{
public string TheProperty { get { return "CLR - TheProperty"; } }我将TextBlock绑定到TheProperty。当我..。
我看到"CLR - TheProperty“和预期的一样。
[TypeDescriptionProvider]我看到"MyPropertyDescriptor - TheProperty“和预期的一样。
ICustomTypeDescriptor我看到"MyPropertyDescriptor - TheProperty“和预期的一样。
ICustomTypeDescriptor和INotifyPropertyChanged我看到"MyPropertyDescriptor - TheProperty“和预期的一样。
[TypeDescriptionProvider]和INotifyPropertyChanged我看到了"CLR - TheProperty“。为什么会这样?奇怪的是,正常显示没有CLR属性的自定义属性。我的自定义类型描述符还返回一个"MyPropertyDescriptor - AnotherProperty“,它在所有情况下都能工作,因为没有定义CLR AnotherProperty .。
总之,考虑到这个XAML
<StackPanel>
<TextBlock Text="{Binding TheProperty}" />
<TextBlock Text="{Binding AnotherProperty}" />
</StackPanel>AnotherProperty始终按预期工作,因为模型没有名为"AnotherProperty“的CLR属性。当TheProperty和INotifyPropertyChanged都被使用时,除了之外,[TypeDescriptionProvider]的工作方式与预期的一样。
这是完整代码。它有点长,但是大部分都是不相关的,这是System.ComponentModel所需要的
public partial class TestWindow : Window
{
public TestWindow()
{
InitializeComponent();
DataContext = new MyModel();
}
}
//[TypeDescriptionProvider(typeof(MyProvider))]
class MyModel : Object
//, INotifyPropertyChanged
//, ICustomTypeDescriptor
{
public string TheProperty { get { return "CLR - TheProperty"; } }
public event PropertyChangedEventHandler PropertyChanged;
public AttributeCollection GetAttributes()
{
return TypeDescriptor.GetAttributes(this);
}
public string GetClassName()
{
return TypeDescriptor.GetClassName(this);
}
public string GetComponentName()
{
return TypeDescriptor.GetComponentName(this);
}
public TypeConverter GetConverter()
{
return TypeDescriptor.GetConverter(this);
}
public EventDescriptor GetDefaultEvent()
{
return TypeDescriptor.GetDefaultEvent(this);
}
public PropertyDescriptor GetDefaultProperty()
{
return TypeDescriptor.GetDefaultProperty(this);
}
public object GetEditor(Type editorBaseType)
{
return TypeDescriptor.GetEditor(this, editorBaseType);
}
public EventDescriptorCollection GetEvents(Attribute[] attributes)
{
return TypeDescriptor.GetEvents(this, attributes);
}
public EventDescriptorCollection GetEvents()
{
return TypeDescriptor.GetEvents(this);
}
public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
{
return TypeDescriptor.GetProperties(this, attributes);
}
public PropertyDescriptorCollection GetProperties()
{
return MyTypeDescriptor.GetCustomProperties();
}
public object GetPropertyOwner(PropertyDescriptor pd)
{
return this;
}
}
class MyProvider : TypeDescriptionProvider
{
public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
{
return new MyTypeDescriptor();
}
}
class MyTypeDescriptor : CustomTypeDescriptor
{
public override PropertyDescriptorCollection GetProperties()
{
return GetCustomProperties();
}
public static PropertyDescriptorCollection GetCustomProperties()
{
return new PropertyDescriptorCollection(
new[] {
new MyPropertyDescriptor("TheProperty"),
new MyPropertyDescriptor("AnotherProperty")
});
}
}
class MyPropertyDescriptor : PropertyDescriptor
{
public MyPropertyDescriptor(string propName)
: base(propName, null)
{
}
public override bool CanResetValue(object component)
{
return false;
}
public override Type ComponentType
{
get { return typeof(MyModel); }
}
public override object GetValue(object component)
{
return "MyPropertyDescriptor - " + Name;
}
public override bool IsReadOnly
{
get { return true; }
}
public override Type PropertyType
{
get { return typeof(string); }
}
public override void ResetValue(object component)
{
throw new InvalidOperationException("cannot reset value");
}
public override void SetValue(object component, object value)
{
throw new InvalidOperationException("property is readonly");
}
public override bool ShouldSerializeValue(object component)
{
return true;
}
}发布于 2012-05-17 11:46:22
老问题,但对于那些寻找答案的人来说。
问题在于System.Windows.PropertyPath.ResolvePropertyName(String,对象、类型、对象、布尔值)私有方法。我在PresentationFramework.dll的.NET 4.0中找到了它。
从.NET反射器中提取:
object propertyHelper = DependencyProperty.FromName(str, ownerType);
if ((propertyHelper == null) && (item is ICustomTypeDescriptor))
{
propertyHelper = TypeDescriptor.GetProperties(item)[str];
}
if ((propertyHelper == null) && ((item is INotifyPropertyChanged) || (item is DependencyObject)))
{
propertyHelper = this.GetPropertyHelper(ownerType, str);
}
if (propertyHelper == null)
{
propertyHelper = TypeDescriptor.GetProperties(item)[str];
}
if (propertyHelper == null)
{
propertyHelper = this.GetPropertyHelper(ownerType, str);
}
if ((propertyHelper == null) && throwOnError)
{
throw new InvalidOperationException(SR.Get("PropertyPathNoProperty", new object[] { ownerType.Name, str }));
}
return propertyHelper;如您所见,检索属性标识符(DependencyProperty / PropertyDescriptor / PropertyInfo)如下:
H 110否则使用获取,H 211H 112否则抛出异常或返回空。H 213G 214因此,如果item实现INotifyPropertyChanged接口,System.Refl展/PropertyInfo将获得优先于TypeDescriptor/PropertyDescriptor的优先级。我认为他们选择这种策略是出于性能原因,因为PropertyInfo比PropertyDescriptor轻得多。
解决问题的方法是实现ICustomTypeDescriptor (最好是显式的),以便将ICustomTypeDescriptor方法调用传递给适当的TypeDescriptor方法调用,但不是使用对象参数,而是使用类型参数(this.GetType())。这样,您的TypeDescriptionProvider将被使用。
https://stackoverflow.com/questions/8112943
复制相似问题