[Silverlight入门系列]使用MVVM模式(7):ViewModel的INotifyPropertyChanged接口实现
本文说说ViewModel的这个INotifyPropertyChanged接口可以用来做啥?
举例1:我有个TabControl,里面放了很多View,每个由ViewModel控制,我想是想TabSelectionChanged就打开相应的ViewModel,怎么做?
解答:用ViewModel的INotifyPropertyChanged接口实现,因为TabItem作为一个选择器就有 IsSelected属性,把这个属性绑定到ViewModel的IsSelected字段,然后这个字段改变的时候用INotifyPropertyChanged接口实现通知即可。整个流程用MVVM实现非常整洁。
Xaml
1 <TabControl ...>
2 <TabControl.ItemContainerStyle>
3 <Style TargetType="{x:Type TabItem}">
4 <Setter Property="IsSelected"
5 Value="{Binding Path=IsSelected,Mode=TwoWay}"/>
6 </Style>
7 </TabControl.ItemContainerStyle>
8 </TabControl>
2 <TabControl.ItemContainerStyle>
3 <Style TargetType="{x:Type TabItem}">
4 <Setter Property="IsSelected"
5 Value="{Binding Path=IsSelected,Mode=TwoWay}"/>
6 </Style>
7 </TabControl.ItemContainerStyle>
8 </TabControl>
ViewModel
1 publicclass MyViewModel : INotifyPropertyChanged
2 {
3 privatebool _isLoaded;
4
5 privatevoid Load()
6 {
7 // code
8 }
9
10 privatebool _isSelected;
11
12 publicbool IsSelected
13 {
14 get
15 {
16 returnthis._isSelected;
17 }
18 set
19 {
20 if (this._isSelected != value)
21 {
22 this._isSelected = value;
23
24 if (this._isSelected &&!this._isLoaded)
25 {
26 this.Load();
27 this._isLoaded =true;
28 }
29
30 var propertyChanged =this.PropertyChanged;
31 if (propertyChanged !=null)
32 {
33 propertyChanged(this, new PropertyChangedEventArgs("IsSelected"));
34 }
35 }
36 }
37 }
38
39 publicevent PropertyChangedEventHandler PropertyChanged;
40 }
2 {
3 privatebool _isLoaded;
4
5 privatevoid Load()
6 {
7 // code
8 }
9
10 privatebool _isSelected;
11
12 publicbool IsSelected
13 {
14 get
15 {
16 returnthis._isSelected;
17 }
18 set
19 {
20 if (this._isSelected != value)
21 {
22 this._isSelected = value;
23
24 if (this._isSelected &&!this._isLoaded)
25 {
26 this.Load();
27 this._isLoaded =true;
28 }
29
30 var propertyChanged =this.PropertyChanged;
31 if (propertyChanged !=null)
32 {
33 propertyChanged(this, new PropertyChangedEventArgs("IsSelected"));
34 }
35 }
36 }
37 }
38
39 publicevent PropertyChangedEventHandler PropertyChanged;
40 }
举例2:我有个TreeView,里面的项非常复杂,还需要惰性加载(点击了才取数据并展开),怎么用MVVM实现?彻底晕了
解答:还是用ViewModel的INotifyPropertyChanged接口实现,要使得你的视图没有代码,就要你不再把TreeView当成一个存储数据的地方,而是看做一个展现数据的地方,那么一切都将水到渠成。这就是ViewModel这个想法的由来。而用INotifyPropertyChanged接口可以神奇的实现它们之间的解耦。
Xaml
1 <TreeView ItemsSource="{Binding FirstGeneration}">
2 <TreeView.ItemContainerStyle>
3 <!--
4 This Style binds a TreeViewItem to a PersonViewModel.
5 -->
6 <Style TargetType="{x:Type TreeViewItem}">
7 <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}"/>
8 <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
9 <Setter Property="FontWeight" Value="Normal"/>
10 <Style.Triggers>
11 <Trigger Property="IsSelected" Value="True">
12 <Setter Property="FontWeight" Value="Bold"/>
13 </Trigger>
14 </Style.Triggers>
15 </Style>
16 </TreeView.ItemContainerStyle>
17
18 <TreeView.ItemTemplate>
19 <HierarchicalDataTemplate ItemsSource="{Binding Children}">
20 <TextBlock Text="{Binding Name}"/>
21 </HierarchicalDataTemplate>
22 </TreeView.ItemTemplate>
23 </TreeView>
2 <TreeView.ItemContainerStyle>
3 <!--
4 This Style binds a TreeViewItem to a PersonViewModel.
5 -->
6 <Style TargetType="{x:Type TreeViewItem}">
7 <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}"/>
8 <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
9 <Setter Property="FontWeight" Value="Normal"/>
10 <Style.Triggers>
11 <Trigger Property="IsSelected" Value="True">
12 <Setter Property="FontWeight" Value="Bold"/>
13 </Trigger>
14 </Style.Triggers>
15 </Style>
16 </TreeView.ItemContainerStyle>
17
18 <TreeView.ItemTemplate>
19 <HierarchicalDataTemplate ItemsSource="{Binding Children}">
20 <TextBlock Text="{Binding Name}"/>
21 </HierarchicalDataTemplate>
22 </TreeView.ItemTemplate>
23 </TreeView>
ViewModel
1 publicclass PersonViewModel
2 {
3 public PersonViewModel(Person person)
4 : this(person, null)
5 {
6 }
7
8 private PersonViewModel(Person person, PersonViewModel parent)
9 {
10 _person = person;
11 _parent = parent;
12
13 _children =<span styl%
2 {
3 public PersonViewModel(Person person)
4 : this(person, null)
5 {
6 }
7
8 private PersonViewModel(Person person, PersonViewModel parent)
9 {
10 _person = person;
11 _parent = parent;
12
13 _children =<span styl%