首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么在实现TypeDescriptionProviderAttribute时,WPF似乎要绕过INotifyPropertyChanged?

为什么在实现TypeDescriptionProviderAttribute时,WPF似乎要绕过INotifyPropertyChanged?
EN

Stack Overflow用户
提问于 2011-11-13 16:28:48
回答 1查看 1.8K关注 0票数 2

我正在尝试使用[TypeDescriptionProviderAttribute],以便为类提供一个自定义类型描述符。这是可行的,但是当我实现INotifyPropertyChanged时,WPF似乎忽略了自定义类型描述符,直接查找CLR属性(如果存在的话)。下面是一个片段,稍后我将粘贴完整的示例:

代码语言:javascript
复制
//[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“和预期的一样。

  • 使用ICustomTypeDescriptorINotifyPropertyChanged

我看到"MyPropertyDescriptor - TheProperty“和预期的一样。

  • 使用[TypeDescriptionProvider]INotifyPropertyChanged

我看到了"CLR - TheProperty“。为什么会这样?奇怪的是,正常显示没有CLR属性的自定义属性。我的自定义类型描述符还返回一个"MyPropertyDescriptor - AnotherProperty“,它在所有情况下都能工作,因为没有定义CLR AnotherProperty .。

总之,考虑到这个XAML

代码语言:javascript
复制
<StackPanel>
    <TextBlock Text="{Binding TheProperty}" />
    <TextBlock Text="{Binding AnotherProperty}" />
</StackPanel>

AnotherProperty始终按预期工作,因为模型没有名为"AnotherProperty“的CLR属性。当ThePropertyINotifyPropertyChanged都被使用时,除了之外,[TypeDescriptionProvider]的工作方式与预期的一样。

这是完整代码。它有点长,但是大部分都是不相关的,这是System.ComponentModel所需要的

代码语言:javascript
复制
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;
    }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-05-17 11:46:22

老问题,但对于那些寻找答案的人来说。

问题在于System.Windows.PropertyPath.ResolvePropertyName(String,对象、类型、对象、布尔值)私有方法。我在PresentationFramework.dll的.NET 4.0中找到了它。

从.NET反射器中提取:

代码语言:javascript
复制
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)如下:

  1. 尝试获取DependencyProperty,如果项目实现ICustomTypeDescriptor,则使用
  2. ,如果项目实现ICustomTypeDescriptor,则使用TypeDescriptor获取PropertyDescriptor,如果项目实现INotifyPropertyChanged或DependencyObject,则使用
  3. ,使用System.Reflection获取PropertyInfo,使用
  4. 来获取DependencyProperty,使用
  5. 来获取DependencyProperty,使用
  6. 使用H 110否则使用获取,H 211H 112否则抛出异常或返回空。H 213G 214

因此,如果item实现INotifyPropertyChanged接口,System.Refl展/PropertyInfo将获得优先于TypeDescriptor/PropertyDescriptor的优先级。我认为他们选择这种策略是出于性能原因,因为PropertyInfo比PropertyDescriptor轻得多。

解决问题的方法是实现ICustomTypeDescriptor (最好是显式的),以便将ICustomTypeDescriptor方法调用传递给适当的TypeDescriptor方法调用,但不是使用对象参数,而是使用类型参数(this.GetType())。这样,您的TypeDescriptionProvider将被使用。

票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8112943

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档