关于依赖属性的验证回调

这里,不讨论强制值回调和属性更改,有关内容参见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 [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)调用的是带有属性更改回调的构造函数。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值