[WPF]WPF中如何实现数据与表示分离。(二) —— Binding(上)
2006-01-20 09:31 Colin Han 阅读(3914) 评论(0) 编辑 收藏 举报
在我的上一篇文章:[WPF]WPF中如何实现数据与表示分离。(一) —— XAML 中,我简单介绍了如何使用XAML描述应用程序的界面。比较遗憾的是,那篇文章其实和数据与表示分离的主题似乎不大。这一篇文章中,我们将重点讨论WPF的Binding功能。
还是用ColorPicker来作为例子。现在我们需要将它的数据层和表示层进行划分。在这个例子中,数据层的业务逻辑很简单:能够根据给入的三个变量生成一个颜色值。如果将它描述为一个对象,可能是下面的结构。
然后表示层通过一定的途径将这些信息展示出来。
于是,我们编写了如下的展示层XAML文件,试图让它能够很好的展示这个数据对象。
我们来看一下在WPF中是如何实现这种衔接的。下面的是完整的数据展示层XAML。
在行10-12中,我们将一个ColorPickerData数据包作为一个资源嵌入到这个XAML中来。并且将Grid的当前数据内容映射到这个数据包上(行13-15声明)。
然后将后面的三个Slider的Value属性分别绑在数据包的几个不同的属性上。将Border的Background也绑定到数据包的Background属性上。
Ok,看起来展示层已经描述的很清楚了。WPF项目组的一个PM(产品经理)看着这个设计露出了非常满足的笑容。清晰,明了,解决了大多数的用户需求。如果你是WPF项目组中的一个开发人员,现在你一定会跳得很高。
“不可能,我怎么知道数据层什么时候变化了?”
“不可能,你所描述的结构,我必须使用反射来读取数据,这样的性能将是无法接受的。”
“不可能…………”你想了想,说:“对不起,麻烦问一下,‘{Binding Path=Blue}’似乎没有见过,代表什么呢?” -_-!
Ok,这一切都是可能的。在下一篇文章里,我们将讨论微软是如何解决这些问题的。
还是用ColorPicker来作为例子。现在我们需要将它的数据层和表示层进行划分。在这个例子中,数据层的业务逻辑很简单:能够根据给入的三个变量生成一个颜色值。如果将它描述为一个对象,可能是下面的结构。
1
public class ColorPickerData
2
{
3
public ColorPickerData()
4
{ }
5
6
byte _red;
7
byte _green;
8
byte _blue;
9
Brush _backgound;
10
11
public byte Red
12
{
13
get { return this._red; }
14
set
15
{
16
this._red = value;
17
OnValueChanged();
18
}
19
}
20
public byte Green
21
{
22
get { return this._green; }
23
set
24
{
25
this._green = value;
26
OnValueChanged();
27
}
28
}
29
public byte Blue
30
{
31
get { return this._blue; }
32
set
33
{
34
this._blue = value;
35
OnValueChanged();
36
}
37
}
38
public Brush Background
39
{
40
get { return this._backgound; }
41
set { this._backgound = value; }
42
}
43
44
private void OnValueChanged()
45
{
46
this._backgound = new SolidColorBrush(Color.FromRgb(this._red, this._green, this._blue));
47
}
48
}
49
(注意:以上代码仅为说明问题。对于实现方式,大家应该都有更好的想法。) 
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

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

然后表示层通过一定的途径将这些信息展示出来。
于是,我们编写了如下的展示层XAML文件,试图让它能够很好的展示这个数据对象。
1
<Window x:Class="ColorPicker2.Window1"
2
xmlns="http://schemas.microsoft.com/winfx/avalon/2005"
3
xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005"
4
Title="ColorPicker2"
5
Height="130" Width="300"
6
>
7
<Grid>
8
<Grid.RowDefinitions>
9
<RowDefinition/>
10
<RowDefinition/>
11
<RowDefinition/>
12
</Grid.RowDefinitions>
13
<Grid.ColumnDefinitions>
14
<ColumnDefinition Width="40"/>
15
<ColumnDefinition Width="150"/>
16
<ColumnDefinition/>
17
</Grid.ColumnDefinitions>
18
19
<TextBlock Grid.Column="0" Grid.Row="0">Red:</TextBlock>
20
<Slider Grid.Column="1" Grid.Row="0"
21
Minimum="0" Maximum="255"/>
22
23
<TextBlock Grid.Column="0" Grid.Row="1">Green:</TextBlock>
24
<Slider Grid.Column="1" Grid.Row="1"
25
Minimum="0" Maximum="255"/>
26
27
<TextBlock Grid.Column="0" Grid.Row="2">Blue:</TextBlock>
28
<Slider Grid.Column="1" Grid.Row="2"
29
Minimum="0" Maximum="255"/>
30
31
<Border Grid.Column="2" Grid.Row="0" Grid.RowSpan="3" Margin="5,5,5,5">
32
<Border BorderThickness="1" CornerRadius="5" BorderBrush="Gray"/>
33
</Border>
34
</Grid>
35
</Window>
现在,看起来结构更加清晰一些了。但是,我们如何让数据层和表示层进行衔接呢?往往这些衔接的逻辑可能会使我们系统的层次界限变得模糊。最终变成了铁板一块。 
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

32

33

34

35

我们来看一下在WPF中是如何实现这种衔接的。下面的是完整的数据展示层XAML。
1
<?Mapping XmlNamespace="local" ClrNamespace="ColorPicker2"?>
2
<Window x:Class="ColorPicker2.Window1"
3
xmlns="http://schemas.microsoft.com/winfx/avalon/2005"
4
xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005"
5
xmlns:l="local"
6
Title="ColorPicker2"
7
Height="130" Width="300"
8
>
9
<Grid>
10
<Grid.Resources>
11
<l:ColorPickerData x:Key="colorPickerData"/>
12
</Grid.Resources>
13
<Grid.DataContext>
14
<Binding Source="{StaticResource colorPickerData}"/>
15
</Grid.DataContext>
16
<Grid.RowDefinitions>
17
<RowDefinition/>
18
<RowDefinition/>
19
<RowDefinition/>
20
</Grid.RowDefinitions>
21
<Grid.ColumnDefinitions>
22
<ColumnDefinition Width="40"/>
23
<ColumnDefinition Width="150"/>
24
<ColumnDefinition/>
25
</Grid.ColumnDefinitions>
26
27
<TextBlock Grid.Column="0" Grid.Row="0">Red:</TextBlock>
28
<Slider Grid.Column="1" Grid.Row="0"
29
Minimum="0" Maximum="255" Value="{Binding Path=Red}"/>
30
31
<TextBlock Grid.Column="0" Grid.Row="1">Green:</TextBlock>
32
<Slider Grid.Column="1" Grid.Row="1"
33
Minimum="0" Maximum="255" Value="{Binding Path=Green}"/>
34
35
<TextBlock Grid.Column="0" Grid.Row="2">Blue:</TextBlock>
36
<Slider Grid.Column="1" Grid.Row="2"
37
Minimum="0" Maximum="255" Value="{Binding Path=Blue}"/>
38
39
<Border Grid.Column="2" Grid.Row="0" Grid.RowSpan="3" Margin="5, 5, 5, 5">
40
<Border BorderThickness="1" CornerRadius="5" BorderBrush="Gray" Background="{Binding Path=Background}"/>
41
</Border>
42
</Grid>
43
</Window>
与前一个XAML不同的地方主要在于黄色标注的部分。
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

32

33

34

35

36

37

38

39

40

41

42

43

在行10-12中,我们将一个ColorPickerData数据包作为一个资源嵌入到这个XAML中来。并且将Grid的当前数据内容映射到这个数据包上(行13-15声明)。
然后将后面的三个Slider的Value属性分别绑在数据包的几个不同的属性上。将Border的Background也绑定到数据包的Background属性上。
Ok,看起来展示层已经描述的很清楚了。WPF项目组的一个PM(产品经理)看着这个设计露出了非常满足的笑容。清晰,明了,解决了大多数的用户需求。如果你是WPF项目组中的一个开发人员,现在你一定会跳得很高。
“不可能,我怎么知道数据层什么时候变化了?”
“不可能,你所描述的结构,我必须使用反射来读取数据,这样的性能将是无法接受的。”
“不可能…………”你想了想,说:“对不起,麻烦问一下,‘{Binding Path=Blue}’似乎没有见过,代表什么呢?” -_-!
Ok,这一切都是可能的。在下一篇文章里,我们将讨论微软是如何解决这些问题的。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix