WPF学习笔记10 依赖属性4

五. 依赖属性回调、验证及强制值

    我们通过下面的这幅图,简单介绍一下WPF属性系统对依赖属性操作的基本步骤:

  借用一个常见的图例,介绍一下WPF属性系统对依赖属性操作的基本步骤: 

  • 第一步,确定Base Value,对同一个属性的赋值可能发生在很多地方。比如控件的背景(Background),可能在Style或者控件的构造函数中都对它进行了赋值,这个Base Value就要确定这些值中优先级最高的值,把它作为Base Value。
  • 第二步,估值。如果依赖属性值是计算表达式(Expression),比如说一个绑定,WPF属性系统就会计算表达式,把结果转化成一个实际值。
  • 第三步,动画。动画是一种优先级很高的特殊行为。如果当前属性正在作动画,那么因动画而产生的值会优于前面获得的值,这个也就是WPF中常说的动画优先。
  • 第四步,强制。如果我们在FrameworkPropertyMetadata中传入了 CoerceValueCallback委托,WPF属性系统会回调我们传入的的delagate,进行属性值的验证,验证属性值是否在我们允许的范围之内。例如强制设置该值必须大于于0小于10等等。在属性赋值过程中,Coerce拥有 最高的优先级,这个优先级要大于动画的优先级别。
  • 第五步,验证。验证是指我们注册依赖属性如果提供了ValidateValueCallback委托,那么最后WPF会调用我们传入的delegate,来验证数据的有效性。当数据无效时会抛出异常来通知。

  那么应该如何使用这些功能呢? 

前面我们讲了基本的流程,下面我们就用一个小的例子来进行说明:

XAML的代码如下:

<Window x:Class="WpfApp1.WindowValid"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        Title=" WindowValid " Height="300" Width="400">

    <Grid>

        <StackPanel>     

            <Button Name="btnDPTest" Click="btnDPTest_Click" >属性值执行顺序测试</Button>
        </StackPanel>

    </Grid>

</Window>

C#的代码如下:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Shapes;

using System.Windows.Threading;

using WpfApp1.Models;

 

namespace WpfApp1

{

    /// <summary>

    /// WindowThd.xaml 的交互逻辑

    /// </summary>

    public partial class WindowValid: Window

    {

        public WindowValid ()

        {

            InitializeComponent();

    }
    private void btnDPTest_Click(object sender, RoutedEventArgs e)
    {

        SimpleDP test = new SimpleDP();

        test.ValidDP = 1;

    } 

    }

}

 

 

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

 

namespace WpfApp1.Models

{

    public class SimpleDP : DependencyObject

    {

        public static readonly DependencyProperty ValidDPProperty =

            DependencyProperty.Register("ValidDP", typeof(int), typeof(SimpleDP),

                new FrameworkPropertyMetadata(0,

                    FrameworkPropertyMetadataOptions.None,

                    new PropertyChangedCallback(OnValueChanged),

                    new CoerceValueCallback(CoerceValue)),

                    new ValidateValueCallback(IsValidValue));

 

        public int ValidDP

        {

            get { return (int)GetValue(ValidDPProperty); }

            set { SetValue(ValidDPProperty, value); }

        }

 

        private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)

        {

            Console.WriteLine("当属性值的OnValueChanged方法被调用,属性值为: {0}", e.NewValue);

        }

 

        private static object CoerceValue(DependencyObject d, object value)

        {

            Console.WriteLine("当属性值的CoerceValue方法被调用,属性值强制为: {0}", value);

            return value;

        }

 

        private static bool IsValidValue(object value)

        {

            Console.WriteLine("当属性值的IsValidValue方法被调用,对属性值进行验证,返回bool值,如果返回True表示严重通过,否则会以异常的形式抛出: {0}", value);

            return true;

        } 

    }

}

 当ValidDP属性变化之后,PropertyChangeCallback就会被调用。可以看到结果并没有完全按照我们先前的流程先 Coerce后Validate的顺序执行,有可能是WPF内部做了什么特殊处理,当属性被修改时,首先会调用Validate来判断传入的value是 否有效,如果无效就不继续后续的操作,这样可以更好的优化性能。从上面的结果上看出,CoerceValue后面并没有立即ValidateValue, 而是直接调用了PropertyChanged。这是因为前面已经验证过了value,如果在Coerce中没有改变value,那么就不用再验证了。如 果在 Coerce中改变了value,那么这里还会再次调用ValidateValue操作,和前面的流程图执行的顺序一样,在最后我们会调用 ValidateValue来进行最后的验证,这就保证最后的结果是我们希望的那样了。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值