【转】【WPF】关于依赖属性的ValidateValueCallback,PropertyChangedCallback和CoerceValueCallback的执行顺序

三个回调对应依赖属性的验证过程,改变过程和强制转换过程。

复制代码
class Dobj : DependencyObject
{
    //依赖属性包装
    public int MyProperty
    {
        get { return (int)GetValue(MyPropertyProperty); }
        set { SetValue(MyPropertyProperty, value); }
    }

    //注册依赖属性
    //注意依赖属性默认值是:71
    public static readonly DependencyProperty MyPropertyProperty =
        DependencyProperty.Register("MyProperty", typeof(int), typeof(Dobj), new PropertyMetadata(71, PropertyChanged, CoerceValue), ValidateValue);

    //属性改变
    static void PropertyChanged(DependencyObject dobj, DependencyPropertyChangedEventArgs e)
    {
        Debug.WriteLine(String.Format("PropertyChanged - 属性:{0} 新值:{1} 旧值:{2}", e.Property.Name, e.NewValue, e.OldValue));
    }

    //强制转换
    static object CoerceValue(DependencyObject dobj, object newValue)
    {
        Debug.WriteLine(String.Format("CoerceValue - {0}", newValue));
        return newValue;
    }

    //验证
    static bool ValidateValue(object obj)
    {
        Debug.WriteLine(String.Format("ValidateValue - {0}", obj));
        return true;
    }
}
复制代码

当仅仅定义一个新对象时:

var dobj = new Dobj();

调试下输出:

ValidateValue - 71
ValidateValue - 71

验证过程被执行了两次,我不知道为什么这样。

接着修改这个对象的属性。

var dobj = new Dobj();
dobj.MyProperty = 999;

输出:

ValidateValue - 71
ValidateValue - 71
ValidateValue - 999
CoerceValue - 999
PropertyChanged - 属性:MyProperty 新值:999 旧值:71

默认值被验证了两遍,接着验证新值,强制转换,最后属性改变回调。

接下来修改一下验证回调,把返回值改为false。

//验证
static bool ValidateValue(object obj)
{
    Debug.WriteLine(String.Format("ValidateValue - {0}", obj));
    if ((int)obj == 999)
        return false;
    return true;
}

赋值语句(SetValue方法)会抛出ArgumentException异常,消息:’999′ is not a valid value for property ‘MyProperty’.(999并不是MyProperty属性的合法值)。

下面要做到内容是创建一个当前依赖对象的继承类,并改写父类依赖属性的元数据。

代码:

复制代码
//继承原来的依赖对象
class SuperDobj : Dobj
{
    static SuperDobj()
    {
        //改写父类依赖属性的元数据,默认值改成81
        Dobj.MyPropertyProperty.OverrideMetadata(typeof(SuperDobj), new PropertyMetadata(81, PropertyChanged, CoerceValue));
    }

    //属性改变
    static void PropertyChanged(DependencyObject dobj, DependencyPropertyChangedEventArgs e)
    {
        Debug.WriteLine(String.Format("SuperDobj.PropertyChanged - 属性:{0} 新值:{1} 旧值:{2}", e.Property.Name, e.NewValue, e.OldValue));
    }

    //强制转换
    static object CoerceValue(DependencyObject dobj, object newValue)
    {
        Debug.WriteLine(String.Format("SuperDobj.CoerceValue - {0}", newValue));
        if ((int)newValue == 999)
            throw new Exception("test");
        return newValue;
    }
}
复制代码

还是像刚才,先定义一个对象:

var superdobj = new SuperDobj();

输出:

ValidateValue - 71
ValidateValue - 71
ValidateValue – 81

父类和子类的验证都要执行一遍。

接着设置子类的依赖属性:

var superdobj = new SuperDobj();
superdobj.MyProperty = 999;

输出:

ValidateValue - 71
ValidateValue - 71
ValidateValue - 81
ValidateValue - 999
SuperDobj.CoerceValue - 999
PropertyChanged - 属性:MyProperty 新值:999 旧值:81
SuperDobj.PropertyChanged - 属性:MyProperty 新值:999 旧值:81

这个结果很有意思。

看来子类和父类的验证和属性改变回调都会依次被调用,但是强制转换只调用子类的。

事实上属性元数据此时会调用PropertyMetadata.Merge方法来合并多个属性元数据。可以参考MSDN:http://msdn.microsoft.com/zh-cn/library/system.windows.propertymetadata.merge.aspx

 

 原文地址:https://www.mgenware.com/blog/?p=188

posted on   梦琪小生  阅读(2813)  评论(0编辑  收藏  举报

编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
历史上的今天:
2013-10-16 C# 如何使用NPOI操作Excel以及读取合并单元格等
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

导航

统计

点击右上角即可分享
微信分享提示