refer to: http://tech.ddvip.com/2009-05/1241599368117968.html
WPF数据绑定为应用程序提供了一种表示数据和与数据交互的简单而又一致的方法。元素能够以公共语言运行库 (CLR) 对象和 XML 的形式绑定到各种数据源中的数据。
一、数据绑定的基本概念:
数据绑定涉及到两个方面:一个是绑定源,再一个是绑定目标。绑定源即控件绑定所使用的源数据,绑定目标即数据显示的控件。
1、对于绑定源,在WPF可以是以下四种:
CLR对象:可以绑定到CLR类的公开的属性、子属性、索引器上
ADO.Net对象:例如DataTable、DataView等
XML文件:使用XPath进行解析
DependencyObject:绑定到其依赖项属性上,即控件绑定控件
2、对于绑定目标,必须是WPF中的DependencyObject,将数据绑定到其依赖项属性上。
二、绑定的基本方式
根据数据流的方向,WPF中的数据绑定分为以下四种:
OneWay 绑定导致对源属性的更改会自动更新目标属性,但是对目标属性的更改不会传播回源属性。此绑定类型适用于绑定的控件为隐式只读控件的情况。例如,您可能绑定到如股票行情自动收录器这样的源,或许目标属性没有用于进行更改的控件接口(如表的数据绑定背景色)。如果无需监视目标属性的更改,则使用 OneWay 绑定模式可避免 TwoWay 绑定模式的系统开销。
TwoWay 绑定导致对源属性的更改会自动更新目标属性,而对目标属性的更改也会自动更新源属性。此绑定类型适用于可编辑窗体或其他完全交互式 UI 方案。大多数属性都默认为 OneWay 绑定,但是一些依赖项属性(通常为用户可编辑的控件的属性,如 TextBox 的 Text 属性和 CheckBox 的 IsChecked 属性)默认为 TwoWay 绑定。确定依赖项属性绑定在默认情况下是单向还是双向的编程方法是:使用 GetMetadata 获取属性的属性元数据,然后检查 BindsTwoWayByDefault 属性的布尔值。
OneWayToSource 与 OneWay 绑定相反;它在目标属性更改时更新源属性。一个示例方案是您只需要从 UI 重新计算源值的情况。
OneTime绑定 ,该绑定会导致源属性初始化目标属性,但不传播后续更改。这意味着,如果数据上下文发生了更改,或者数据上下文中的对象发生了更改,则更改会反映在目标属性中。如果您使用的数据的当前状态的快照适于使用,或者这些数据是真正静态的,则适合使用此绑定类型。如果要使用源属性中的某个值初始化目标属性,并且事先不知道数据上下文,则也可以使用此绑定类型。此绑定类型实质上是 OneWay 绑定的简化形式,在源值不更改的情况下可以提供更好的性能。
每个依赖项属性的默认值都不同。一般情况下,用户可编辑控件属性(例如文本框和复选框的属性)默认为双向绑定,而多数其他属性默认为单向绑定。确定依赖项属性绑定在默认情况下是单向还是双向的编程方法是:使用 GetMetadata 来获取属性的属性元数据,然后检查 BindsTwoWayByDefault 属性的布尔值。
三、实现数据源更改影响目标更改
如果要实现数据源更改时,改变目标的值(即上图中的OneWay方式及TwoWay方式的由绑定源到绑定目标方向的数据绑定),需使数据源对象实现System.ComponentModel命名空间的INotifyPropertyChanged接口。INotifyPropertyChanged接口中定义了一个PropertyChanged事件,在某属性值发生变化时引发此事件,即可通知绑定目标更改其显示的值。例如:
1
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
1:
using
System.ComponentModel;
2:
3:
namespace
BasicWPFDataBinding
4: {
5:
public
class
MyData : INotifyPropertyChanged
6: {
7: #region INotifyPropertyChanged Members
8:
public
event
PropertyChangedEventHandler PropertyChanged;
9: #endregion
10:
11:
public
MyData()
12: {
13: Name =
"Tom"
;
14: }
15:
16:
private
string
_Name;
17:
public
string
Name
18: {
19:
set
20: {
21: _Name = value;
22:
23:
if
(PropertyChanged !=
null
)
24: {
25:
// 引发PropertyChanged事件,
26:
// PropertyChangedEventArgs构造方法中的参数字符串表示属性名
27: PropertyChanged(
this
,
new
PropertyChangedEventArgs(
"Name"
));
28: }
29: }
30:
get
31: {
32:
return
_Name;
33: }
34: }
35: }
36: }
|
四、实现绑定目标的值更改影响绑定源的值
若实现实现绑定目标的值更改影响绑定源的值(即上图中TwoWay的由绑定目标到绑定源方向,及OneWayToSource),可以设置相应控件绑定时的UpdateSourceTrigger的值,其值有三种:
PropertyChanged:当绑定目标属性更改时,立即更新绑定源。
LostFocus:当绑定目标元素失去焦点时,更新绑定源。
Explicit:仅在调用 UpdateSource 方法时更新绑定源。
多数依赖项属性的UpdateSourceTrigger 值的默认值为 PropertyChanged,而 Text 属性的默认值为 LostFocus。
例如:
1
|
1: <TextBox Text=
"{Binding Path=Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
/>
|
五、示例:
下面的示例使用第3节中的MyData类作为数据源,演示基于4种绑定方式的执行效果:
XAML代码如下:
1
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
|
1: <Window x:Class=
"BasicWPFDataBinding.WinBasicBinding"
3: xmlns:x=
"http://schemas.microsoft.com/winfx/2006/xaml"
4: xmlns:c=
"clr-namespace:BasicWPFDataBinding"
5: Title=
"WinBasicBinding"
Height=
"360"
Width=
"360"
>
6: <Grid>
7: <Grid.ColumnDefinitions>
8: <ColumnDefinition/>
9: <ColumnDefinition/>
10: </Grid.ColumnDefinitions>
11: <Grid.RowDefinitions>
12: <RowDefinition/>
13: <RowDefinition/>
14: </Grid.RowDefinitions>
15: <StackPanel Grid.Row=
"0"
Grid.Column=
"0"
x:Name=
"panelOneTime"
>
16: <StackPanel.Resources>
17: <c:MyData x:Key=
"myDataSourceA"
/>
18: </StackPanel.Resources>
19: <StackPanel.DataContext>
20: <Binding Source=
"{StaticResource myDataSourceA}"
/>
21: </StackPanel.DataContext>
22: <TextBlock Text=
"OneTime Binding"
/>
23: <TextBox Margin=
"5"
Text=
"{Binding Path=Name, Mode=OneTime}"
/>
24: <Button Margin=
"5"
Content=
"Change Name"
25: x:Name=
"btnOneTimeBindingChange"
Click=
"btnOneTimeBindingChange_Click"
/>
26: <Button Margin=
"5"
Content=
"Get Name"
27: x:Name=
"btnOnTimeBindingGet"
Click=
"btnOnTimeBindingGet_Click"
/>
28: </StackPanel>
29: <StackPanel Grid.Row=
"0"
Grid.Column=
"1"
x:Name=
"panelOneWay"
>
30: <StackPanel.Resources>
31: <c:MyData x:Key=
"myDataSourceB"
/>
32: </StackPanel.Resources>
33: <StackPanel.DataContext>
34: <Binding Source=
"{StaticResource myDataSourceB}"
/>
35: </StackPanel.DataContext>
36: <TextBlock Text=
"OneWay Binding"
/>
37: <TextBox Margin=
"5"
38: Text=
"{Binding Path=Name, Mode=OneWay}"
/>
39: <Button Margin=
"5"
Content=
"Change Name"
40: x:Name=
"btnOneWayeBindingChange"
Click=
"btnOneWayeBindingChange_Click"
/>
41: <Button Margin=
"5"
Content=
"Get Name"
42: x:Name=
"btnOneWayBindingGet"
Click=
"btnOneWayBindingGet_Click"
/>
43: </StackPanel>
44: <StackPanel Grid.Row=
"1"
Grid.Column=
"0"
x:Name=
"panelTwoWay"
>
45: <StackPanel.Resources>
46: <c:MyData x:Key=
"myDataSourceC"
/>
47: </StackPanel.Resources>
48: <StackPanel.DataContext>
49: <Binding Source=
"{StaticResource myDataSourceC}"
/>
50: </StackPanel.DataContext>
51: <TextBlock Text=
"TwoWay Binding"
/>
52: <TextBox Margin=
"5"
53: Text=
"{Binding Path=Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
/>
54: <Button Margin=
"5"
Content=
"Change Name"
55: x:Name=
"btnTwoWayBindingChange"
Click=
"btnTwoWayBindingChange_Click"
/>
56: <Button Margin=
"5"
Content=
"Get Name"
57: x:Name=
"btnTwoWayBindingGet"
Click=
"btnTwoWayBindingGet_Click"
/>
58: <TextBlock Margin=
"5"
59: Text=
"{Binding Path=Name, Mode=OneWay}"
/>
60: </StackPanel>
61: <StackPanel Grid.Row=
"1"
Grid.Column=
"1"
x:Name=
"panelOneWayToSource"
>
62: <StackPanel.Resources>
63: <c:MyData x:Key=
"myDataSourceD"
/>
64: </StackPanel.Resources>
65: <StackPanel.DataContext>
66: <Binding Source=
"{StaticResource myDataSourceD}"
/>
67: </StackPanel.DataContext>
68: <TextBlock Text=
"OneWayToSource Binding"
/>
69: <TextBox Margin=
"5"
70: Text=
"{Binding Path=Name, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}"
/>
71: <Button Margin=
"5"
Content=
"Change Name"
72: x:Name=
"btnOneWayToSourceBindingChange"
Click=
"btnOneWayToSourceBindingChange_Click"
/>
73: <Button Margin=
"5"
Content=
"Get Name"
74: x:Name=
"btnOneWayToSourceBindingGet"
Click=
"btnOneWayToSourceBindingGet_Click"
/>
75: <TextBlock Margin=
"5"
76: Text=
"{Binding Path=Name, Mode=OneWay}"
/>
77: </StackPanel>
78: </Grid>
79: </Window>
|
代码文件如下:
1
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
|
1:
using
System.Windows;
2:
3:
namespace
BasicWPFDataBinding
4: {
5:
/// <summary>
6:
/// Interaction logic for WinBasicBinding.xaml
7:
/// </summary>
8:
public
partial
class
WinBasicBinding : Window
9: {
10:
public
WinBasicBinding()
11: {
12: InitializeComponent();
13: }
14:
15: #region OneTime绑定
16:
private
void
btnOneTimeBindingChange_Click(
object
sender, RoutedEventArgs e)
17: {
18: MyData source = (MyData)(panelOneTime.DataContext);
19: source.Name =
"Jerry"
;
20:
21: MessageBox.Show(
22:
"myData.Name has been changed to Jerry"
,
23:
"System Information"
,
24: MessageBoxButton.OK,
25: MessageBoxImage.Information);
26: }
27:
28:
private
void
btnOnTimeBindingGet_Click(
object
sender, RoutedEventArgs e)
29: {
30: MyData source = (MyData)(panelOneTime.DataContext);
31:
32:
string
name = source.Name;
33:
34: MessageBox.Show(
35:
string
.Format(
"myData.Name value is {0}."
, name),
36:
"System Information"
,
37: MessageBoxButton.OK,
38: MessageBoxImage.Information);
39: }
40: #endregion
41:
42: #region OneWay绑定
43:
private
void
btnOneWayeBindingChange_Click(
object
sender, RoutedEventArgs e)
44: {
45: MyData source = (MyData)(panelOneWay.DataContext);
46: source.Name =
"Jerry"
;
47:
48: MessageBox.Show(
49:
"myData.Name has been changed to Jerry"
,
50:
"System Information"
,
51: MessageBoxButton.OK,
52: MessageBoxImage.Information);
53: }
54:
55:
private
void
btnOneWayBindingGet_Click(
object
sender, RoutedEventArgs e)
56: {
57: MyData source = (MyData)(panelOneWay.DataContext);
58:
59:
string
name = source.Name;
60:
61: MessageBox.Show(
62:
string
.Format(
"myData.Name value is {0}."
, name),
63:
"System Information"
,
64: MessageBoxButton.OK,
65: MessageBoxImage.Information);
66: }
67: #endregion
68:
69: #region TwoWay绑定
70:
private
void
btnTwoWayBindingChange_Click(
object
sender, RoutedEventArgs e)
71: {
72: MyData source = (MyData)(panelTwoWay.DataContext);
73: source.Name =
"Jerry"
;
74:
75: MessageBox.Show(
76:
"myData.Name has been changed to Jerry"
,
77:
"System Information"
,
78: MessageBoxButton.OK,
79: MessageBoxImage.Information);
80: }
81:
82:
private
void
btnTwoWayBindingGet_Click(
object
sender, RoutedEventArgs e)
83: {
84: MyData source = (MyData)(panelTwoWay.DataContext);
85:
86:
string
name = source.Name;
87:
88: MessageBox.Show(
89:
string
.Format(
"myData.Name value is {0}."
, name),
90:
"System Information"
,
91: MessageBoxButton.OK,
92: MessageBoxImage.Information);
93: }
94: #endregion
95:
96: #region OneWayToSource绑定
97:
private
void
btnOneWayToSourceBindingChange_Click(
object
sender, RoutedEventArgs e)
98: {
99: MyData source = (MyData)(panelOneWayToSource.DataContext);
100: source.Name =
"Jerry"
;
101:
102: MessageBox.Show(
103:
"myData.Name has been changed to Jerry"
,
104:
"System Information"
,
105: MessageBoxButton.OK,
106: MessageBoxImage.Information);
107: }
108:
109:
private
void
btnOneWayToSourceBindingGet_Click(
object
sender, RoutedEventArgs e)
110: {
111: MyData source = (MyData)(panelOneWayToSource.DataContext);
112:
113:
string
name = source.Name;
114:
115: MessageBox.Show(
116:
string
.Format(
"myData.Name value is {0}."
, name),
117:
"System Information"
,
118: MessageBoxButton.OK,
119: MessageBoxImage.Information);
120: }
121: #endregion
122: }
123: }
|
程序执行,我们可以得到如下的结论:
对于OneTime绑定:在界面中显示的为数据源的初始值,更改数据源的值的时候,不会更改界面的数据显示;更改界面的数据也不会影响到数据源的数据。
对于OneWay绑定:在界面中显示的数据可以随数据源的值的变化而变化,但更改界面的数据不会影响到数据源。
对于TwoWay绑定:界面中显示的数据及数据源的数据可以双向显示及更新。
对于OneWayToSource绑定:初始时界面的数据为空;更改界面的数据可以影响数据源的值,但是更改数据源的值不会体现在界面上。