[Silverlight入门系列]使用MVVM模式(7):ViewModel的INotifyPropertyChanged接口实现

本文说说ViewModel的这个INotifyPropertyChanged接口可以用来做啥?

 

举例1:我有个TabControl,里面放了很多View,每个由ViewModel控制,我想是想TabSelectionChanged就打开相应的ViewModel,怎么做?

解答:用ViewModel的INotifyPropertyChanged接口实现,因为TabItem作为一个选择器就有 IsSelected属性,把这个属性绑定到ViewModel的IsSelected字段,然后这个字段改变的时候用INotifyPropertyChanged接口实现通知即可。整个流程用MVVM实现非常整洁。

ExpandedBlockStart.gifXaml
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>
ExpandedBlockStart.gifViewModel
1 public class MyViewModel : INotifyPropertyChanged
2 {
3 private bool _isLoaded;
4
5 private void Load()
6 {
7 // code
8   }
9
10 private bool _isSelected;
11
12 public bool IsSelected
13 {
14 get
15 {
16 return this._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 public event PropertyChangedEventHandler PropertyChanged;
40 }

 

举例2:我有个TreeView,里面的项非常复杂,还需要惰性加载(点击了才取数据并展开),怎么用MVVM实现?彻底晕了

解答:还是用ViewModel的INotifyPropertyChanged接口实现,要使得你的视图没有代码,就要你不再把TreeView当成一个存储数据的地方,而是看做一个展现数据的地方,那么一切都将水到渠成。这就是ViewModel这个想法的由来。而用INotifyPropertyChanged接口可以神奇的实现它们之间的解耦。

ExpandedBlockStart.gifXaml
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>

ExpandedBlockStart.gifViewModel
1 public class 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 = new ReadOnlyCollection<PersonViewModel>(
14 (from child in _person.Children
15 select new PersonViewModel(child, this))
16 .ToList<PersonViewModel>());
17 }
18
19 private bool _isSelected;
20 public bool IsSelected
21 {
22 get { return _isSelected; }
23 set
24 {
25 if (value != _isSelected)
26 {
27 _isSelected = value;
28 this.OnPropertyChanged("IsSelected");
29 }
30 }
31 }
32
33 private bool _isExpanded;
34 public bool IsExpanded
35 {
36 get { return _isExpanded; }
37 set
38 {
39 if (value != _isExpanded)
40 {
41 _isExpanded = value;
42 this.OnPropertyChanged("IsExpanded");
43 }
44
45 // Expand all the way up to the root.
46   if (_isExpanded && _parent != null)
47 _parent.IsExpanded = true;
48 }
49 }
50 public string Name
51 {
52 get { return _person.Name; }
53 }
54 }
55  public class Person
56 {
57 readonly List<Person> _children = new List<Person>();
58 public IList<Person> Children
59 {
60 get { return _children; }
61 }
62
63 public string Name { get; set; }
64 }

按需加载:

ExpandedBlockStart.gifView Code
1 interface ITreeViewItemViewModel : INotifyPropertyChanged
2 {
3 ObservableCollection<TreeViewItemViewModel> Children { get; }
4 bool HasDummyChild { get; }
5 bool IsExpanded { get; set; }
6 bool IsSelected { get; set; }
7 TreeViewItemViewModel Parent { get; }
8 }
9  public TreeViewItemViewModel : ITreeViewItemViewModel
10 {
11 protected TreeViewItemViewModel(TreeViewItemViewModel parent, bool lazyLoadChildren)
12 {
13 _parent = parent;
14
15 _children = new ObservableCollection<TreeViewItemViewModel>();
16
17 if (lazyLoadChildren)
18 _children.Add(DummyChild);
19 }
20 public bool IsExpanded
21 {
22 get { return _isExpanded; }
23 set
24 {
25 if (value != _isExpanded)
26 {
27 _isExpanded = value;
28 this.OnPropertyChanged("IsExpanded");
29 }
30
31 // Expand all the way up to the root.
32   if (_isExpanded && _parent != null)
33 _parent.IsExpanded = true;
34
35 // Lazy load the child items, if necessary.
36   if (this.HasDummyChild)
37 {
38 this.Children.Remove(DummyChild);
39 this.LoadChildren();
40 }
41 }
42 }
43
44  /// <summary>
45  /// Returns true if this object's Children have not yet been populated.
46  /// </summary>
47  public bool HasDummyChild
48 {
49 get { return this.Children.Count == 1 && this.Children[0] == DummyChild; }
50 }
51
52  /// <summary>
53  /// Invoked when the child items need to be loaded on demand.
54  /// Subclasses can override this to populate the Children collection.
55  /// </summary>
56  protected virtual void LoadChildren()
57 {
58 }
59 }

真正加载子项的工作留给子类去实现。它们重载LoadChildren方法来提供一个跟类型相关的加载子项的实现。比如下面的RegionViewModel类,它重载了该方法来加载State对象并且创建StateViewModel对象。

ExpandedBlockStart.gifView Code
1 public class RegionViewModel : TreeViewItemViewModel
2 {
3 readonly Region _region;
4
5 public RegionViewModel(Region region)
6 : base(null, true)
7 {
8 _region = region;
9 }
10
11 public string RegionName
12 {
13 get { return _region.RegionName; }
14 }
15
16 protected override void LoadChildren()
17 {
18 foreach (State state in Database.GetStates(_region))
19 base.Children.Add(new StateViewModel(state, this));
20 }
21 }
ExpandedBlockStart.gifXaml
1 <TreeView ItemsSource="{Binding Regions}">
2 <TreeView.ItemContainerStyle>
3 <!--
4 This Style binds a TreeViewItem to a TreeViewItemViewModel.
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.Resources>
19 <HierarchicalDataTemplate
20 DataType="{x:Type local:RegionViewModel}"
21 ItemsSource="{Binding Children}"
22 >
23 <StackPanel Orientation="Horizontal">
24 <Image Width="16" Height="16"
25 Margin="3,0" Source="Images"Region.png" />
26 <TextBlock Text="{Binding RegionName}" />
27 </StackPanel>
28 </HierarchicalDataTemplate>
29
30 <HierarchicalDataTemplate
31 DataType="{x:Type local:StateViewModel}"
32 ItemsSource="{Binding Children}"
33 >
34 <StackPanel Orientation="Horizontal">
35 <Image Width="16" Height="16"
36 Margin="3,0" Source="Images"State.png" />
37 <TextBlock Text="{Binding StateName}" />
38 </StackPanel>
39 </HierarchicalDataTemplate>
40
41 <DataTemplate DataType="{x:Type local:CityViewModel}">
42 <StackPanel Orientation="Horizontal">
43 <Image Width="16" Height="16"
44 Margin="3,0" Source="Images"City.png" />
45 <TextBlock Text="{Binding CityName}" />
46 </StackPanel>
47 </DataTemplate>
48 </TreeView.Resources>
49  </TreeView>

未完待续。

转载于:https://www.cnblogs.com/Areas/archive/2011/09/07/2169890.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/361987.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

无状态Spring安全性第1部分:无状态CSRF保护

如今&#xff0c;随着RESTful架构变得越来越标准&#xff0c;可能值得花一些时间重新考虑当前的安全方法。 在这个小系列的博客文章中&#xff0c;我们将探索一些以无状态方式解决与Web相关的安全问题的相对较新的方法。 这第一篇文章是关于保护您的网站免受跨站请求伪造&#…

window.Event参数详解

原文地址&#xff1a;window.Event参数详解作者&#xff1a;cz0090704window.evet 说明 event代表事件的状态&#xff0c;例如触发event对象的元素、鼠标的位置及状态、按下的键等等。 event对象只在事件发生的过程中才有效。 event的某些属性只对特定的事件有意义。比如&…

微信群运营之设计运营思路

商家要想运营好微信群&#xff0c;那么首要做的工作就是设计运营思路。如果做事毫无章法思路&#xff0c;那么很有可能会让自己的工作陷入僵局。运营微信群并不简单&#xff0c;需要考虑多方面社群鸭因素。卖什么产品&#xff0c;群管理体系的设立&#xff0c;规则的制定&#…

阅读react-redux源码(七) - 实现一个react-redux

阅读react-redux源码 - 零阅读react-redux源码 - 一阅读react-redux源码(二) - createConnect、match函数的实现阅读react-redux源码(三) - mapStateToPropsFactories、mapDispatchToPropsFactories和mergePropsFactories阅读react-redux源码(四) - connectAdvanced、wrapWithC…

[读书笔记]TCP/IP详解V1读书笔记-4 5

IP地址与以太网地址之间的关系 R P发送一份称作A R P请求的以太网数据帧给以太网上的每个主机。这个过程称作广播&#xff0c;在32 bit的I P地址和采用不同网络技术的硬件地址之间提供动态映射 ----------------------------------------- arp以太网帧的类型字段为x 0 8 0 6&am…

未来是Apache Karaf上的微服务架构

这是Jamie Goodyear的客座博客文章&#xff08; 博客 &#xff0c; icbts &#xff09;。 他是Savoir Technologies的开源倡导者&#xff0c;Apache开发人员和计算机系统分析师&#xff1b; 他为全球大型组织设计&#xff0c;批判和支持了体系结构。 他拥有纽芬兰纪念大学的计…

springcloud微服务多节点高性能、高可用、高并发部署

1. 共有三个服务 discovery服务&#xff0c;domain服务&#xff0c;gateway服务。 discovery服务是用来注册其他服务的&#xff0c;作为服务治理用。 domain服务是主业务服务。 gateway服务是所有服务的一个入口&#xff0c;用来做一些服务的判断和过滤用。 2. 有三台机器分别为…

只能是数字、字母、-和_

在文本框的keypress事件调用下面函数。 如 <input disabled"disabled" type"text" iduserNameToEdit οnkeypress"TextValidate()" /> 如果在文本框中按下特殊字符键&#xff0c;则显示警告信息&#xff0c;或者输入框不接受非法输入。 …

代码风格之Prettier简介

多人协作中统一的代码风格有利于项目的发展这是共识&#xff0c;但是采用什么标准来统一代码这选择就相对纷杂。项目刚开始使用了ESLint来规范代码&#xff0c;但是ESLint默认是支持JavaScript&#xff0c;加上配置可以支持TypeScript&#xff0c;而样式的支持则需要再配置Styl…

带有Swagger的Spring Rest API –集成和配置

如今&#xff0c;公开的API终于获得了应有的关注&#xff0c;公司也开始意识到其战略价值。 但是&#xff0c;使用第三方API确实是一项繁琐的工作&#xff0c;尤其是当这些API维护不当&#xff0c;设计不当或缺少任何文档时。 这就是为什么我决定四处寻找可以为集成编程人员和其…

A customized combobox with JQuery

要求实现一个轻量级的在客户端筛选的combobox&#xff0c;支持大数据量&#xff08;超过1000个items&#xff09;&#xff0c;能快速检索内容&#xff0c;并支持数据的设置和活动等基本操作。在这之前尝试过使用Jquery UI的Autocomplete&#xff0c;但是当数据量太大时客户端检…

使用内存回流的方法来实现将image的内容转换为 byte[]

在今天的开发中老大不知道怎么突发奇想&#xff0c;要使用Image的Byte数据。当时使用老几种方式效果均不理想&#xff0c;最后发现其实可以使用内存回流的方式来实现。多的不说老&#xff0c;马上贴上代码&#xff1a;/**//// <summary> /// 将byte[]转换为Image…

TypeScript中的class声明了什么

在初看TypeScript的时候在这里卡住的时间难以估计&#xff0c;并不能很好的理解”换个角度说&#xff0c;我们可以认为类具有 实例部分与 静态部分这两个部分。“这句话。今天再回头看这部分文档&#xff0c;在同事的帮助下突然有了比较通透的理解。 class Greeter {static st…

CentOS 6下搭建Apache+MySQL+PHP+SSL

网上的一些文章都已经比较老了&#xff0c;现在版本高了之后&#xff0c;其实配置是很省力的&#xff08;不考虑什么负载的话&#xff09; 分享全过程&#xff0c;出了文中提到的安装epel rpmfushion 源指令不同外&#xff0c;其他的过程也适用与Centos 5 1.安装CentOS 6 ,可以…

通过设计国际象棋游戏来了解策略模式

今天&#xff0c;我们将借助一个示例来尝试了解策略模式。 我们将考虑的示例是国际象棋游戏。 这里的目的是解释策略模式&#xff0c;而不是构建全面的国际象棋游戏解决方案。 策略模式&#xff1a;策略模式被称为行为模式-用于管理对象之间的算法&#xff0c;关系和职责。 策…

vs2010 问题 LINK : fatal error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏

vs2010 问题 LINK : fatal error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏 在安装 VS2010 后&#xff0c;再安装 VS2012 VS2015 等&#xff0c;原来的 .NET 4.0 会被替换为 .NET 4.5。不会恢复 .NET 4.0 。这时&#xff0c;VS2010的 cvtres.exe 就无法使用了。如果 PATH…

Nginx 使用try_files遇到的问题

背景&#xff1a; root /some/path; location / {try_files $uri $uri/ /dist/index.html; }使用React之类的的库来开发前端页面的时候&#xff0c;因为是单页应用所以需要上面的Nginx配置&#xff0c;用来在找不到html文件的时候内部重定向到/dist/index.html文件。 服务器上…

群发邮件

最近&#xff0c;通过两周的学习&#xff0c;对.net 的基础知识有了进一步的了解。觉得自己可以写个小程序了。于是花了两天时间写了一个 群发邮件的一个WinForm小程序。自己在这里小秀一下&#xff0c;表扬及鼓励一下自己。哈哈&#xff01; 此小程序在发送邮件的基础上还添加…

深入研究ES6 Generators

ES6 Generators系列&#xff1a; ES6 Generators基本概念深入研究ES6 GeneratorsES6 Generators的异步应用ES6 Generators并发 如果你还不知道什么是ES6 generators&#xff0c;请看我的前一篇文章“ES6 Generators基本概念” 。如果你已经对它有所了解&#xff0c;本文将带你…

在JavaEE中使用CDI的简单面向方面的编程(AOP)

我们编写满足特定业务逻辑的服务API。 涵盖所有服务API&#xff08;如安全性&#xff0c;日志记录&#xff0c;审核&#xff0c;度量延迟等&#xff09;的跨领域问题很少。 这是一个重复的非业务代码&#xff0c;可以在其他方法之间重用。 重用的一种方法是将这些重复的代码移入…