win8学习之数据绑定
首先,打开VS2012,然后新建一个工程,命名为TimeTable。
点击确定后,选择模拟器运行环境:
试试看你的应用程序是否能够正常运行,可以的话,继续下面的步骤。
开发之前我们先细想一下这个工程,要做的是要把课程的数据显示出来,那么就要用到数据绑定了。熟悉wp7和silverlight开发的朋友,接下来你就会发现,在win8(XAML+c#)开发当中,数据绑定是一样的。
首先,我们修改下我们的工程,新建一个命名为Resources.然后在 文件夹右键–添加–新建项,选取资源字典。命名为:MyDictionary.xaml。添加一行画刷来作为背景。并且修改代码如下:
1
2
3
4
5
6
7
8
9
10
11
|
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:TimeTable.Resources">
<SolidColorBrush
Color="#0099FF"
x:Key="AppBackgroundColor"/>
</ResourceDictionary>
|
现在打开App.xaml。添加对MyDicitonary.xaml的声明。修改如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<ResourceDictionary.MergedDictionaries>
<!--
Styles
that define common
aspects of the
platform look and
feel
Required
by Visual Studio
project and
item templates
-->
<ResourceDictionary
Source="Common/StandardStyles.xaml"/>
<ResourceDictionary
Source="Resources/MyDictionary.xaml"/>
</ResourceDictionary.MergedDictionaries>
|
现在修改MainPage.xaml的grid的背景。
1
|
<Grid
Background="{StaticResource AppBackgroundColor}">
|
现在,就能看到背景色变为了蓝色。接下来就进行数据定义吧。我们的数据类都继承INotifyPropertyChanged接口,以便数据更新的时候能够自己通知控件更新。添加一个Data的文件夹。然后新建添加三个类,分别是ViewModel.cs,WeekdayItem.cs,ScheduleItem.cs .
代码如下:
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
|
class
ViewModel :
INotifyPropertyChanged
{
private
ObservableCollection<WeekdayItem>
weekdayList;
public
ObservableCollection<WeekdayItem>
WeekdayList {
get {
return weekdayList;
} }
private
int selectedItemIndex;
public
int SelectedItemIndex
{
get
{ return
selectedItemIndex;
}
set
{ selectedItemIndex
= value;
NotifyPropertyChanged("SelectedItemIndex");
}
}
public
ViewModel()
{
weekdayList
= new
ObservableCollection<WeekdayItem>();
selectedItemIndex
= -1;
}
public
event PropertyChangedEventHandler
PropertyChanged;
private
void NotifyPropertyChanged(string
propName)
{
if
(PropertyChanged
!= null)
{
PropertyChanged(this,
new PropertyChangedEventArgs(propName));
}
}
}
|
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
|
class
WeekdayItem :
INotifyPropertyChanged
{
private
ObservableCollection<ScheduleItem>
scheduleList;
private
int scheduleSelected;
public
int ScheduleSelected
{
get
{ return
scheduleSelected;
}
set
{ scheduleSelected
= value;
NotifyPropertyChanged("ScheduleSelected");
}
}
public
ObservableCollection<ScheduleItem>
ScheduleList
{
get
{ return
scheduleList;
}
}
public
WeekdayItem()
{
scheduleList
= new
ObservableCollection<ScheduleItem>();
weekday
= "Monday";
}
private
string weekday;
public
string Weekday
{
get
{ return
weekday;
}
set
{ weekday
= value;
NotifyPropertyChanged("WeekDay");
}
}
public
event PropertyChangedEventHandler
PropertyChanged;
private
void NotifyPropertyChanged(string
propName)
{
if
(PropertyChanged
!= null)
{
PropertyChanged(this,
new PropertyChangedEventArgs(propName));
}
}
}
|
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
|
class
ScheduleItem :
INotifyPropertyChanged
{
private
string lessonName;
public
string LessonName
{
get
{ return
lessonName;
}
set
{
lessonName
= value;
NotifyPropertyChanged("LessonName");
}
}
private
string startTime;
public
string StartTime
{
get
{
return
startTime;
}
set
{
startTime
= value;
NotifyPropertyChanged("StartTme");
}
}
private
string endTime;
public
string EndTime
{
get
{ return
endTime;
}
set
{
endTime
= value;
NotifyPropertyChanged("EndTime");
}
}
private
string classRoom;
public
string ClassRoom
{
get
{ return
classRoom;
}
set
{ classRoom
= value;
NotifyPropertyChanged("ClassRoom");
}
}
public
event PropertyChangedEventHandler
PropertyChanged;
private
void NotifyPropertyChanged(string
propName)
{
if
(PropertyChanged
!= null)
{
PropertyChanged(this,
new PropertyChangedEventArgs(propName));
}
}
}
|
上面的代码已经很清楚了。就不多说了。
温馨提示:要用到InotifyPropertyChanged接口,必须先引用System.ComponentModel命名空间哦,还有动态数据集合ObservableCollection也需要引用System.Collections.ObjectModel命名空间的哦,不然看到红色下划波浪线还傻傻不知道什么事。还有一点需要说明的是,InotifyPropertyChanged接口在以前的开发中用的是Windows.UI.Xaml.Data命名空间,在WinRT下变成了System.ComponentModel了,谨记!另外本教程涉及到文件夹下的文件,命名空间不统一,如果你要在MainPage里调用Data文件夹里的文件,必须添加命名空间TimeTable.Data,下面将要建立的Pages文件夹同理。
下面进行数据绑定。首先,在MyDictionary.xaml的SolidColorBrush的下面添加下面一段代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<Style
x:Key="WeekdayListStyle"
TargetType="TextBlock"
BasedOn="{Binding BasicTextStyle}"
>
<Setter
Property="FontSize"
Value="45"/>
<Setter
Property="FontWeight"
Value="Light"/>
<Setter
Property="Margin"
Value="10,0"/>
<Setter
Property="VerticalAlignment"
Value="Center"/>
</Style>
<DataTemplate
x:Key="WeekdayListItemTemplate">
<TextBlock
Text="{Binding Weekday}"
Style="{StaticResource WeekdayListStyle}"/>
</DataTemplate>
|
上面定义了一个数据模板,BasicTextStyle定义在Common/StandardStyles.xaml里面,这个文件里面定义了很多style。
下面修改MainPage的Grid。
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
|
<Grid
Background="{StaticResource AppBackgroundColor}">
<Grid.ColumnDefinitions>
<ColumnDefinition
/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<StackPanel
Grid.RowSpan="2">
<TextBlock
x:Name="WeekdayListTitle"
Style="{StaticResource HeaderTextStyle}"
Margin="10"
Text="星期列表"/>
<ListView
x:Name="weekdayList" Grid.RowSpan="2"
ItemsSource="{Binding WeekdayList}"
ItemTemplate="{StaticResource WeekdayListItemTemplate}"
>
</ListView>
</StackPanel>
<StackPanel
Orientation="Vertical"
Grid.Column="1"
Grid.RowSpan="2">
<TextBlock
Style="{StaticResource HeaderTextStyle}"
Margin="10"
x:Name="ItemDetailTitle"
Text="课程细节"/>
<Frame
x:Name="ItemDetailFrame"/>
</StackPanel>
</Grid>
|
上面定义的style除了自己定义的,基本都是在Common/StandardStyles.xaml里面。熟悉数据绑定的能在上面的代码看到熟悉的代码影吧。绑定了ListView的ItemsSource和ItemTemplate。下面的Frame标签以后再讲。
然后修改后台的构造函数和添加一个函数来往viewModel添加数据。
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
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
|
ViewModel
viewModel;
public
MainPage()
{
viewModel
= new
ViewModel();
addData();
this.DataContext
= viewModel;
this.InitializeComponent();
}
/// <summary>
/// 往viewModel添加数据
/// </summary>
private
void addData()
{
WeekdayItem
monday =
new WeekdayItem();
monday.ScheduleList.Add(new
ScheduleItem
{
ClassRoom
= "B-215",
StartTime
= "8:30",
EndTime
= "10:00",
LessonName
= "数学"
});
monday.ScheduleList.Add(new
ScheduleItem
{
ClassRoom
= "B-216",
StartTime
= "10:30",
EndTime
= "12:00",
LessonName
= "物理"
});
monday.ScheduleList.Add(new
ScheduleItem
{
ClassRoom
= "E-303",
StartTime
= "14:30",
EndTime
= "16:00",
LessonName
= "计算机"
});
monday.Weekday
= "星期一";
viewModel.WeekdayList.Add(monday);
WeekdayItem
tuesday =
new WeekdayItem();
tuesday.Weekday
= "星期二";
tuesday.ScheduleList.Add(new
ScheduleItem
{
ClassRoom
= "B-215",
StartTime
= "8:30",
EndTime
= "10:00",
LessonName
= "数学"
});
tuesday.ScheduleList.Add(new
ScheduleItem
{
ClassRoom
= "B-216",
StartTime
= "10:30",
EndTime
= "12:00",
LessonName
= "物理"
});
tuesday.ScheduleList.Add(new
ScheduleItem
{
ClassRoom
= "E-303",
StartTime
= "14:30",
EndTime
= "16:00",
LessonName
= "英语"
});
viewModel.WeekdayList.Add(tuesday);
WeekdayItem
wednesday =
new WeekdayItem();
wednesday.Weekday
= "星期三";
wednesday.ScheduleList.Add(new
ScheduleItem
{
ClassRoom
= "B-215",
StartTime
= "8:30",
EndTime
= "10:00",
LessonName
= "数学"
});
wednesday.ScheduleList.Add(new
ScheduleItem
{
ClassRoom
= "B-216",
StartTime
= "10:30",
EndTime
= "12:00",
LessonName
= "物理"
});
wednesday.ScheduleList.Add(new
ScheduleItem
{
ClassRoom
= "E-303",
StartTime
= "14:30",
EndTime
= "16:00",
LessonName
= "英语"
});
viewModel.WeekdayList.Add(wednesday);
WeekdayItem
thursday =
new WeekdayItem();
thursday.Weekday
= "星期四";
thursday.ScheduleList.Add(new
ScheduleItem
{
ClassRoom
= "B-215",
StartTime
= "8:30",
EndTime
= "10:00",
LessonName
= "数学"
});
thursday.ScheduleList.Add(new
ScheduleItem
{
ClassRoom
= "B-216",
StartTime
= "10:30",
EndTime
= "12:00",
LessonName
= "物理"
});
thursday.ScheduleList.Add(new
ScheduleItem
{
ClassRoom
= "E-303",
StartTime
= "14:30",
EndTime
= "16:00",
LessonName
= "英语"
});
viewModel.WeekdayList.Add(thursday);
WeekdayItem
friday =
new WeekdayItem();
friday.Weekday
= "星期五";
friday.ScheduleList.Add(new
ScheduleItem
{
ClassRoom
= "B-215",
StartTime
= "8:30",
EndTime
= "10:00",
LessonName
= "数学"
});
friday.ScheduleList.Add(new
ScheduleItem
{
ClassRoom
= "B-216",
StartTime
= "10:30",
EndTime
= "12:00",
LessonName
= "物理"
});
friday.ScheduleList.Add(new
ScheduleItem
{
ClassRoom
= "E-303",
StartTime
= "14:30",
EndTime
= "16:00",
LessonName
= "英语"
});
viewModel.WeekdayList.Add(friday);
}
|
在构造函数,我们指定了当前页面的信息源DataContext为当前声明的viewModel。现在编译运行,就能看到运行结果如下:
下面我们要使用frame这个标签了。其实,每个页面都有这个Frame这个属性,这个Frame直接控制了导航,导航在Wp7里是用navigationService来完成的。不过可能是由于平板的屏幕大,所以用这个Frame标签就可以做到局部导航。使之可以所有操作都在一个页面完成。不过,如果开发者不实现导航返回按钮,win8平板就中间一个window键。如果能够返回上一层页面?至少我还没发现什么操作可以实现。
下面先给ListView添加一个SelectionChanged事件。当选项改变时触发。
1
2
3
4
5
|
private
void weekdayList_SelectionChanged_1(object
sender,
SelectionChangedEventArgs e)
{
viewModel.SelectedItemIndex
= weekdayList.SelectedIndex;
}
|
只做了一件事,就是修改了viewModel的SelectedItemIndex的值。那么我们要注册一个PropertyChanged事件,监听当这个SelectedItemIndex改变的时候做相应的工作。
在Mainpage的构造函数最后添加:
|
上面我们监听了SelectedItemIndex。当改变的时候使ItemDetailFrame这个Frame导航到不同的页面。这个navigate方法,由VS2012的智能提示就知道,可以带参数,也可以不带参数。
下面我们新建一个文件夹Pages。然后添加一个空页面NoItemSelected.xaml。修改代码如下:
1
2
3
4
5
|
<Grid
Background="{StaticResource AppBackgroundColor}">
<TextBlock
Style="{StaticResource HeaderTextStyle}"
FontSize="30"
Text="No Item Selected"/>
</Grid>
|
然后再添加一个空白页ItemDetail.xaml到Pages文件夹。修改代码如下:
1
2
3
4
5
|
<Grid
Background="{StaticResource AppBackgroundColor}">
<ListView
x:Name="ScheduleList"
ItemsSource="{Binding ScheduleList}"
IsHoldingEnabled="True"
ItemTemplate="{StaticResource ScheduleListItemTemplate}"/>
</Grid>
|
然后修改ItemDetail页面的OnNavigateTo方法并添加一个变量。
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
|
ViewModel
viewModel;
protected
override void
OnNavigatedTo(NavigationEventArgs
e)
{
viewModel
= e.Parameter
as ViewModel;
this.DataContext
= viewModel.WeekdayList[viewModel.SelectedItemIndex];
viewModel.PropertyChanged
+= (sender,
args)
=>
{
if
(viewModel.SelectedItemIndex
== -1)
{
this.DataContext
= null;
}
else
this.DataContext
= viewModel.WeekdayList[viewModel.SelectedItemIndex];
};
}
|
上面OnNavigateTo方法,在页面进入的时候,就获取页面传递过来的ViewModel这个数据。然后指定当前选择的Weekday为数据源。
上面我们还没定义ItemDetail页面ListView的数据模版。在MyDictionary.xaml添加如下模版:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
<DataTemplate
x:Key="ScheduleListItemTemplate">
<StackPanel
Orientation="Vertical">
<TextBlock
Text="{Binding LessonName}"
FontSize="30"/>
<StackPanel
Orientation="Horizontal">
<TextBlock
Text="{Binding StartTime}"
FontSize="18"/>
<TextBlock
Text="-"
FontSize="18"/>
<TextBlock
Text="{Binding EndTime}"
FontSize="18"/>
</StackPanel>
<TextBlock
Text="{Binding ClassRoom}"
FontSize="30"/>
</StackPanel>
</DataTemplate>
|
这样,编译运行,就能看到选择左边的WeekdayList就能改变右边的ItemDetail部分了。