微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

关于依赖属性的验证回调

这里,不讨论强制值回调和属性更改,有关内容参见msdn;这里着重讨论验证回调。

一、定义依赖属性,初始化属性元数据的认值defaultValue为0.0,代码取自mdsn并作了一点小的改动
public class Gauge : DependencyObject
{
    public static readonly DependencyProperty CurrentReadingProperty = DependencyProperty.Register(
        "CurrentReading",typeof(double),typeof(Gauge),new FrameworkPropertyMetadata(0.0);
        new ValidateValueCallback(IsValidReading)
    );

    public Gauge(int i)
    {
        Console.WriteLine(i);
    }

    public double CurrentReading
    {
        get { return (double)GetValue(CurrentReadingProperty); }
        set { SetValue(CurrentReadingProperty,value); }
    }

    public static bool IsValidReading(object value)
    {
        Console.WriteLine("IsValidReading");
        Double v = (Double)value;
        return (!v.Equals(Double.NegativeInfinity) && !v.Equals(Double.PositiveInfinity));
    }
}

private void buttonSunny_Click_1(object sender,RoutedEventArgs e)
{
 Gauge g = new Gauge(1); //仅仅实例化了一个Gauge对象
}

输出:
IsValidReading 0.0
IsValidReading 0.0
Ctor
其中,回调的方法执行了两次,问题来了,回调方法为什么会执行两次呢?

下面是摘自msdn上的一段文字

如果提供的值对属性有效,回调将返回 true;否则,回调返回 false。 假定按照向属性系统注册的类型,属性的类型是正确的,因此通常不会在回调内执行类型检查。 属性系统可在多种不同操作中使用回调。 其中包括按照认值进行初始类型初始化、通过调用 SetValue 进行编程更改或尝试使用提供的新认值重写元数据。 如果验证回调是通过其中任何一种操作调用的,并且返回 false,则将会引发异常。 应用程序编写器必须准备处理这些异常。 验证回调常用于验证枚举值,或在属性设置的度量必须大于或等于零时约束整数值或双精度型值。

也就是说,在给属性元数据的defaultValue赋值、调用SetValue设置依赖项属性的本地值的时候,会执行验证回调;那么在什么地方又执行了回调方法呢?往下看

二、不初始化属性元数据的认值defaultValue,其他代码不变
//new FrameworkPropertyMetadata(0.0)
new FrameworkPropertyMetadata()
输出

IsValidReading 0.0
Ctor

在没有初始化defaultValue的情况下,defaultValue的认值为0.0(double类型的认值),此时回调方法只被调用了一次。如此看来,是不是在FrameworkPropertyMetadata的构造函数内部也调用了验证方法,即如果设置了defaultValue,构造函数就会调用验证方法;如果没有设置defaultValue,构造函数就不会调用验证方法。是这样吗?继续往下看

三、初始化依赖属性元数据对象为null,其他代码不变

//new FrameworkPropertyMetadata()
null
输出

IsValidReading 0.0
Ctor

设置了FrameworkPropertyMetadata为空对象,就不存在构造函数,也就不会调用验证方法了。

另外,FrameworkPropertyMetadata有两个只有一个参数的构造函数

public FrameworkPropertyMetadata(object defaultValue);
public FrameworkPropertyMetadata(PropertyChangedCallback propertyChangedCallback);

那么,当使用new FrameworkPropertyMetadata(null)来实例化一个对象的时候,调用的是哪个构造函数呢?继续把上面的代码作一点小小的改动
//null
new FrameworkPropertyMetadata(null)
然后看一下IL代码的.cctor()部分:
.method private hidebysig specialname rtspecialname static 
 void .cctor() cil managed
{
 // 代码大小 54 (0x36)
 .maxstack 8
 IL_0000: ldstr "CurrentReading"
 IL_0005: ldtoken [mscorlib]System.Double
 IL_000a: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
 IL_000f: ldtoken Gauge
 IL_0014: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
 IL_0019: ldnull
 IL_001a: newobj instance void [PresentationFramework]System.Windows.FrameworkPropertyMetadata::.ctor(class [WindowsBase]System.Windows.PropertyChangedCallback)
 IL_001f: ldnull
 IL_0020: ldftn bool Gauge::IsValidReading(object)
 IL_0026: newobj instance void [WindowsBase]System.Windows.ValidateValueCallback::.ctor(object,native int)
 IL_002b: call class [WindowsBase]System.Windows.DependencyProperty [WindowsBase]System.Windows.DependencyProperty::Register(string,class [mscorlib]System.Type,class [WindowsBase]System.Windows.PropertyMetadata,class [WindowsBase]System.Windows.ValidateValueCallback)
 IL_0030: stsfld class [WindowsBase]System.Windows.DependencyProperty Gauge::CurrentReadingProperty
 IL_0035: ret
} // end of method Gauge::.cctor
从IL_0019行到IL_001a行可以看出,new FrameworkPropertyMetadata(null)调用的是带有属性更改回调的构造函数

原文地址:https://www.jb51.cc/javaschema/285209.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐