其实这两天关于写这MVVM思路一直很混乱. 一方面也在整理回顾4月份项目中关于MVVM的使用,当时版本用Silverlight 3. 版本4发布ICommand的支持多少对MVVM应实际应用上产生一定影响. 当然另外一个原因 我在不断回顾过程也发现不少原来项目中存在的实际问题.这些问题出现同时也给我带来一些的关于MVVM在Silverlight运用中思考. 我现在依然不能理清写这篇文章思路. 也有可能整篇文章结构比较混乱,但大都会针对MVVM在Silverlight项目中运用产生一些实际问题作出整理. 同时在技术群和MSN中每天也有不少Dvp会对MVVM使用提出不少问题. 所以这篇文章打算首先以一个简单MVVM Demo切入,然后再对项目中使用MVVM个细节问题点 进行逐个阐述.
本篇会帮助从MVVM了解进入实际编码入门,然后对实际运用细节提出我个人看法解决方式[当然有可能是不成熟 也欢迎提出你的见解]. 如果你认为对MVVM运用已经驾轻就熟 敬请飘过.
<1>为什么要用MVVM?
关于这个问题 我们把它范围更缩小一点 单一放到Silverlight中来看.一方面Silverlight带来很多新的技术体验动画,3D 等 另外一方面我们在编程上UI层就更加细节化了.可定制.同时新特性Binding、Dependency Property、Routed Events、Command、DataTemplate的不断出现,也为原来适用WPF的MVP模式发生转变,Silverlight需要一个适合自己的框架来"武装"自己,新特性的出现加速MVVM基于MVP中演变成型的速度. 这就导致MVVM从MVP(Model-VIEw-Presenter)模式与WPF结合的应用方式时发展演变过来的一种新型架构框架..
<2>如何运用MVVM?
既然MVVM出现时一个不断演变过程,那么它的出现回给我们的原来Silverlight编码产生哪些变化?这个问题我稍后会解释.先让我们学会使用这个MVVM.
<2.1>我们要做什么?
为了达到完整演示使用MVVM整个过程,下面我会写一个小型的DEMO来阐述如何使用MVVM. 在进入编码前又必要了解一下我们这个程序要做什么 具体需求如下:
现在有一个场景:
在工业批量生产中,会使用多台自动化机器,而人的作用就是这些自动化机器的管理者. 管理者通过程控机[监控自动化机器运行状态一种机器] 实时动态采集多台自动化机器的运行状态参数. 来保证机器正常运行. 说明整个控制流程图:
其实这个是一个简单单一流程. 反映到程序中 我们就要通过程控机Com通信端口采集多个自动化机器的运行参数并反映当前运行状况. ok 需求明确了. 那就让我们用MVVM在Silverlight模拟实现.
<2.2>进入编码
MVVM具体进行拆分就可以分为M-V-VM 三个层次,M[Model]—V[VIEw]—VM[viewmodel],第一个M代表数据实体Model,VIEw也是UI. 那么VM来做什么?当我们有了漂亮VIEw和可 *** 作的Model. 用户通过VIEw来与程序进行交互.Silverlight提供了我们良好Binding特性,我们可以把VIEw中控件与Model的特定属性进行Binding *** 作,页面数据就能直接反馈到Model上来,貌似很好,但是实际运用中我们发现,VIEw中可能出现类型有多个,而我们的Model定义属性类型是唯一的, 同时页面数据需要过滤转换处理,这就麻烦了,我们只能修改Model,可是针对多个页面难道我们修改多次吗? 那么也就违反OO编程第一原则ISP类单一职责. 不可取.同时这时的Model也变得臃肿庞大, 后期代码维护代价足以能够折磨你到"抓狂".
这个时候我们才想起有点冷落的VM了,我们可以把VIEw除了显示以外所有活 都交给它来做. 它功能就充分体现了 隔离VIEw与Model直接关联,同时要满足VIEw所有向后台请求数据的需求. 备受冷落的VM终于有了用武之地了.清晰流程图:
我们先通过利用程序检索一下当前机器运行状态,利用VS2010搭建一个Silverlight Application 结构如下:
@L_502_2@
从结构能清晰看出整体数据流向: 用户 *** 作VIEw输入数据,利用Silverlight 4支持的ICommand通过viewmodes访问DataSource数据源,并把相关数据更新给viewmodel的属性,VIEw通过TwoWay双向绑定看到更新数据..
定义VIEw:
有了VIEw我们再来封装Model,我们控制对象是机器Machine 封装成Model:
public class ComMachine { public string ID { get; set; } public string Machinename { get; set; } public string State { get; set; } }
紧跟着定义viewmodel:
/// <summary> /// 测试单一MVVM框架数据流向 /// Author:chenkai Date:2010年8月10日15:35:43 /// </summary> public class Machineviewmodel:INotifyPropertyChanged { #region INotifyPropertyChanged Members public event PropertyChangedEventHandler PropertyChanged; #endregion public Machineviewmodel(List<Models.ComMachine> getcusList) { this.customerList = getcusList; this.queryCommand = new Command.queryDataCommand(this); } //查询数据 private List<Models.ComMachine> customerList = null; //搜索关键字 private string searchKey = string.Empty; public string SearchKey { get { return searchKey; } set { searchKey = value; if (PropertyChanged != null) this.PropertyChanged(this, new PropertyChangedEventArgs("SearchKey")); } } //搜索结果 private string searchResult = string.Empty; public string SearchResult { get { return searchResult; } set { searchResult = value; if (PropertyChanged != null) this.PropertyChanged(this, new PropertyChangedEventArgs("SearchResult")); } } //搜索Command private ICommand queryCommand = null; public ICommand queryCommand { get { return queryCommand; } } //查询数据 public voID queryDate() { if (!string.IsNullOrEmpty(this.searchKey)) { Models.ComMachine queryCustomer = null; foreach (Models.ComMachine getcustomer in DataSource.GetCustomerList()) { if (getcustomer.ID.Equals(this.searchKey)) { queryCustomer = getcustomer; break; } } if (queryCustomer != null) { this.SearchResult = "机器名称:" + queryCustomer.Machinename + Environment.Newline + "可用状态:" + queryCustomer.State; } else { MessageBox.Show("机器编号不存在!"); this.SearchKey = string.Empty; } } else { MessageBox.Show("请输入你要查询的机器编号ID!"); } }
viewmodel完全为VIEw页面做的量身定制的类,实现 INotifyPropertyChanged接口当对viewmodel属性值发生变更时便进行通知. 另外一个很重要地方是就是当VIEw调用Command命令时,需要在viewmodel中进行关联.
通过上面我们能看出VIEw中实现的对viewmode属性Bingding和对查询 *** 作Command调用. 也就是说调用Binding和Command是可以写在XAML中的,而真正定义Binding和Command实现描述的代码却在viewmodel中.
Command定义:
/// <summary> /// 封装命令Command /// </summary> public class queryDataCommand :ICommand { private viewmodels.Machineviewmodel _Customerviewmodel; public queryDataCommand(viewmodels.Machineviewmodel getcustomer) { this._Customerviewmodel = getcustomer; } //ICommand接口成员之一 确定在当前调用CMd状态下是否允许其执行方法 public bool CanExecute(object parameter) { return true;//允许 } //当出现影响是否应执行该命令的更改时发生 public event EventHandler CanExecuteChanged { add{ } remove { } } public voID Execute(object parameter) { //调用Command要执行的方法 this._Customerviewmodel.queryDate(); }
在Silverlight 3版本是XAML页面并不支持直接绑定Command. 在 Silverlight 4 中,buttonBase 和 Hyperlink 支持 Command 和 CommandParameter 属性。Command 属性可以通过{binding}用法引用来自视图模型数据源的 ICommand 实现。 然后由 Silverlight 输入系统在运行时解释该命令。关于更多信息,请参见 ButtonBase.Command或 Hyperlink.Command. 而在WPF中提供常用应用程序所用的命令集,常用的命令集包括:ApplicationCommands,ComponentCommands,NavigationCommands等,SL 4也正在WPF用户强烈呼声在加入对Comnand绑定支持.
SL 3中我们在定义并实现ICommand接口后,调用往往放在类似事件中需要手动处理.这样有什么不好地方?
在没有结合command patter前,用silverlight进行异步调用的确显得很简单,可问题在于如果应用程序再多一些即有多个异步调用的话,我们将就需要添加一些按钮,而问题也就在于我们不能确定哪个调用属于哪个按钮,即行为与UI不能产生直接有效的映射关系,而Silverlight 4Command的全面支持也是完全解除这个调用障碍.
我在技术群中有人曾这样直接问过我一个Command问题:
当一个button按钮有一个Click事件 同时还绑定一个后台调用的Command 当点击按钮时问他们执行顺序? 这个问题当时确实难住了我 平时这样细节没有注意.
经过测试发现调用顺序是: 先调用Click事件 然后才通过程序对Command解析才调用Command 的Excute方法.
还有一个关于Command调用场景问题:
页面有一个button,当该button被点击的时候我们要完成一些 *** 作, 将该 *** 作封装成一个Command并绑定到该button上就可以了,但如果我们要在button被Load的时候执行另外一些 *** 作呢?
问题就出现了,由于button没有直接被Load事件所触发的Command,所以使用Command就无效了.正如一个控件没有某个属性并且在不继承的情况下而采用AttachProperty一样,我们可以采用AttachBehavior.写的很乱啊.
总结以上是内存溢出为你收集整理的杂谈MVVM在Silverlight中应用全部内容,希望文章能够帮你解决杂谈MVVM在Silverlight中应用所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)