[WPF]WPF中如何实现数据与表示分离。(二) —— Binding(下)

前一篇Blog中,WPF项目组的一个产品经理设计出了一个完美的数据绑定的方案,但是WPF项目组的一个开发人员很大声地喊出了三个问题:
“我怎么知道什么时候数据改变?”
“我可能必须利用反射去访问数据,而反射的性能会很低。”
“{Binding Path=Red}是什么东西?”

好在这一切都只是我的一个想象,微软已经为我们提供了解决方案。这里就要引入WPF中的 DependencyProperty的概念了。

在我刚刚开始接触到WPF的 DependencyProperty的时候,仅仅觉得是一个很巧妙的实现,随着学习WPF的深入,也来越觉得 DependencyProperty其实是WPF的核心技术点之一。

DependencyProperty和DependencyObject配合,提供了WPF中基本的数据存储、访问和通知的机制。也正是因为这两个东西的存在,使得XAML,Binding,Animation都成为可能。

让我们来看一下重新实现后的数据层。
 1 None.gif using  System;
 2 None.gif using  System.Windows;
 3 None.gif using  System.Windows.Media;
 4 None.gif
 5 None.gif namespace  ColorPicker2
 6 ExpandedBlockStart.gifContractedBlock.gif dot.gif {
 7InBlock.gif    public class ColorPickerData : DependencyObject
 8ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
 9InBlock.gif        public ColorPickerData()
10ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
11ExpandedSubBlockEnd.gif        }

12InBlock.gif        public static DependencyProperty BackgroundProperty = DependencyProperty.Register(
13InBlock.gif                "Background",
14InBlock.gif                typeof(Brush),
15InBlock.gif                typeof(ColorPickerData),
16InBlock.gif                new PropertyMetadata(new SolidColorBrush(Colors.Black))
17InBlock.gif            );
18InBlock.gif
19InBlock.gif        public static DependencyProperty RedProperty = DependencyProperty.Register(
20InBlock.gif            "Red",
21InBlock.gif            typeof(byte),
22InBlock.gif            typeof(ColorPickerData)
23InBlock.gif            );
24InBlock.gif
25InBlock.gif        public static DependencyProperty GreenProperty = DependencyProperty.Register(
26InBlock.gif            "Green",
27InBlock.gif            typeof(byte),
28InBlock.gif            typeof(ColorPickerData)
29InBlock.gif            );
30InBlock.gif
31InBlock.gif        public static DependencyProperty BlueProperty = DependencyProperty.Register(
32InBlock.gif            "Blue",
33InBlock.gif            typeof(byte),
34InBlock.gif            typeof(ColorPickerData)
35InBlock.gif            );
36InBlock.gif
37InBlock.gif
38InBlock.gif        public Brush Background
39ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
40ExpandedSubBlockStart.gifContractedSubBlock.gif            get dot.gifreturn (Brush)GetValue(BackgroundProperty); }
41ExpandedSubBlockStart.gifContractedSubBlock.gif            set dot.gif{ SetValue(BackgroundProperty, value); }
42ExpandedSubBlockEnd.gif        }

43InBlock.gif
44InBlock.gif        public byte Red
45ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
46ExpandedSubBlockStart.gifContractedSubBlock.gif            get dot.gifreturn (byte)GetValue(RedProperty); }
47ExpandedSubBlockStart.gifContractedSubBlock.gif            set dot.gif{ SetValue(RedProperty, value); }
48ExpandedSubBlockEnd.gif        }

49InBlock.gif
50InBlock.gif        public byte Green
51ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
52ExpandedSubBlockStart.gifContractedSubBlock.gif            get dot.gifreturn (byte)GetValue(GreenProperty); }
53ExpandedSubBlockStart.gifContractedSubBlock.gif            set dot.gif{ SetValue(GreenProperty, value); }
54ExpandedSubBlockEnd.gif        }

55InBlock.gif
56InBlock.gif        public byte Blue
57ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
58ExpandedSubBlockStart.gifContractedSubBlock.gif            get dot.gifreturn (byte)GetValue(BlueProperty); }
59ExpandedSubBlockStart.gifContractedSubBlock.gif            set dot.gif{ SetValue(BlueProperty, value); }
60ExpandedSubBlockEnd.gif        }

61InBlock.gif
62InBlock.gif        protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
63ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
64InBlock.gif            if (e.Property.Equals(RedProperty) ||
65InBlock.gif                e.Property.Equals(GreenProperty) ||
66InBlock.gif                e.Property.Equals(BlueProperty))
67ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
68InBlock.gif                this.Background = new SolidColorBrush(Color.FromRgb(this.Red, this.Green, this.Blue));
69ExpandedSubBlockEnd.gif            }

70InBlock.gif
71InBlock.gif            base.OnPropertyChanged(e);
72ExpandedSubBlockEnd.gif        }

73ExpandedSubBlockEnd.gif    }

74ExpandedBlockEnd.gif}

75 None.gif

在行12-35,我们注册了4个DependencyProperty:RedProperty, GreenProperty, BlueProperty 和 BackgroundProperty。我们也不再使用成员字段去保存这些属性的具体值。而是直接使用DependencyObject上的GetValue和SetValue方法设置和读取值。

当Red, Green, Blue属性发生变化的时候,我们来同步Background属性(1)。同时,DependencyObject也会使用特定的方式向关联的对象(例如:Binding)发出通知。

Ok,通知的问题解决了。我们开发人员以后不再需要去制定或维护这套数据层和表示层通讯的策略。然后,我们就需要解决第二个问题:使用反射获得对象的属性的性能问题。

从前面的Code中,也许细心的你已经发现,我们不再需要使用反射去获得对象的某个属性了。因为DependencyObject已经提供了GetValue和SetValue方法。数据绑定管理者(暂且先这样叫吧)可以通过这两个方法容易的获得或设置任何一个属性的值(2)。而且,前面的属性注册的机制,也让微软有一个机会来优化内部的数据存储,提高性能(3)。剩下的性能问题可能就出在了Boxing和UnBoxing上了,毕竟很多属性都是值类型的。但是,以目前的结构,微软在JIT上对这一部分进行一些专门的优化也并非不可能。个人猜想,具体情况如何,留待各位去研究了。

啊哈,剩下最后一个问题了。{Binding Path=Red}是什么?微软的官方称呼为:MarkupExtension。或者可以翻译为标记扩展。我写过一篇Blog简单的说了如何自定义一个MarkupExtension,虽然当时我没有调通,但是我认为已经概括性的告诉了你,MarkupExtension是如何工作的。

上面的这条语句也就是说,Slider的Value属性的值是由Binding这个MarkupExtension对象提供(ProvideValue)的。

Ok,Clear。但是,这样就够了吗?所有的问题都解决了吗?这样的设计已经是最好的了吗?

“不!”(也许各位的客户也经常这样向你喊。)
“Brush是个什么东西?我的数据模块只关心Color,不关心Brush!”
“Background的更新逻辑太土了。”(就象很多你们碰到的用户一样,用户有时候就希望能有一个非常漂亮的界面。)

没问题,我将在后面的文章中讨论如何改进这些问题,让我们的数据模块和表示层尽量的分离。

最后,附上本节的源代码:ColorPicker2.rar
注意:本文相关的例子都在WinFX 12月CTP下测试通过,因为目前环境限制,没能再今年1月CTP下进行测试,请见谅。



1:其实,这一部分,微软已经为我们提供了更巧妙的途径,留待下一节来讲解吧。
2:其实,不光数据绑定,XAML其实也是使用这两个方法来访问对象的属性的
3:反编译代码后,证实了我的这个设想,微软为DependencyProperty实现了一套高效的Hash值算法来优化存储。

转载于:https://www.cnblogs.com/Cajon/archive/2006/01/20/320591.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值