MVVMLight项目Model View结构及全局视图模型注入器
上一篇我们已经介绍了如何使用nuget把mvvmlight应用到我们的wpf项目中。这篇我们来了解下一个基本的mvvmlight框架所必须的结构和运行模式。
mvvmlight安装之后,我们可以看到简易的框架布局,如上篇,生成了一个viewmodel文件夹,viewmodel层的内容都放在这边,除了main对象的viewmodel之外,还包含一个viewmodellocator文件,
用来注入当前的viewmodel全局实例。
一、先来说说分层结构:
如图:
1、view负责前端展示,与viewmodel进行数据和命令的交互。
2、viewmodel,负责前端视图业务级别的逻辑结构组织,并将其反馈给前端。
3、model,主要负责数据实体的结构处理,与viewmodel进行交互。
根据上述的分层,我们来进行编码。
先建立一个完整三层结构的目录,如图,包含model、view、viewmodel三层文件夹:
1、写一个model,代码如下:
using galasoft.mvvmlight; using system; using system.collections.generic; using system.linq; using system.text; using system.threading.tasks; namespace mvvmlightdemo.model { public class welcomemodel : observableobject { private string introduction; /// <summary> /// 欢迎词 /// </summary> public string introduction { get { return introduction; } set { introduction = value; raisepropertychanged(()=>introduction); } } }
很简单,仅仅是包含一个实体对象,这边注意的的是那他继承了一个父类:observableobject,这个父类的作用就是保证能够检测属性是否被改变。
它实现了inotifypropertychanged接口,通过触发propertychanged事件达到通知ui更改的目的;
所以我们在定义实体对象的时候,只需要调用raisepropertychanged(propertyname)就可以进行属性更改通知了。
所以实体里面定义的每个属性都加上raisepropertychanged(propertyname)的调用,就可以实现对ui的交互更新了。
2、写一个videmodel,来负责跟view的交互。
using galasoft.mvvmlight; using mvvmlightdemo.model; using system; using system.collections.generic; using system.linq; using system.text; using system.threading.tasks; namespace mvvmlightdemo.viewmodel { public class welcomeviewmodel:viewmodelbase { /// <summary> /// 构造函数 /// </summary> public welcomeviewmodel() { welcome = new welcomemodel() { introduction = "hello world!" }; } #region 属性 private welcomemodel welcome; /// <summary> /// 欢迎词属性 /// </summary> public welcomemodel welcome { get { return welcome; } set { welcome = value; raisepropertychanged(()=>welcome); } } #endregion } }
也很简单,包含了一个命名为welcome的welcomemodel属性,继承了viewbasemodel父类,
viewbasemodel同时继承 observableobject类和icleanup接口。所以他同样有inotifypropertychanged接口的能力,
能够通过触发propertychanged事件达到通知view的目的;
构造函数中对 welcome 属性进行了实例化。
3、写一个view,来显示和交互viewmodel。
<window x:class="mvvmlightdemo.view.welcomeview" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" title="welcomeview" height="300" width="300"> <grid> <stackpanel verticalalignment="center" horizontalalignment="center" > <textblock text="{binding welcome.introduction}" fontsize="30" ></textblock> </stackpanel> </grid> </window>
textblock 绑定了 welcome.introduction,所以应该显示welcome对象下的introduction属性。
这时候的viewmodel和view是没有任何关系的,所以我们在code-behind的构造函数中写上如下代码:
using mvvmlightdemo.viewmodel; using system.windows; namespace mvvmlightdemo.view { /// <summary> /// interaction logic for welcomeview.xaml /// </summary> public partial class welcomeview : window { public welcomeview() { initializecomponent(); this.datacontext = new welcomeviewmodel(); } }
把 welcomeviewmodel 赋值给当前视图的数据上下文。所以可以在当前视图中使用viewmodel中所有的公开属性和命令。
执行效果如下:
二、再来说说构造器:
如果使用nuget安装的是完整的一个是mvvm light 框架,而非 mvvm light libraries only的时候,总是会带上viewmodellocator类,并且生成资源字典并加入到了全局资源中。
<application x:class="mvvmlightdemo.app" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" startupuri="view/welcomeview.xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" d1p1:ignorable="d" xmlns:d1p1="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:vm="clr-namespace:mvvmlightdemo.viewmodel" > <application.resources> <resourcedictionary> <vm:viewmodellocator x:key="locator" d:isdatasource="true" /> </resourcedictionary> </application.resources> </application>
所以每次app初始化的时候,就会去初始化viewmodellocator类。
实际上他就是一个很基本的视图模型注入器。在构造器中把使用到的viewmodel统一注册,并生成单一实例。
然后使用属性把它暴露出来,每当我们访问属性的时候,就会返回相应的viewmodel实例。
/* in app.xaml: <application.resources> <vm:viewmodellocator xmlns:vm="clr-namespace:mvvmlightdemo" x:key="locator" /> </application.resources> in the view: datacontext="{binding source={staticresource locator}, path=viewmodelname}" you can also use blend to do all this with the tool's support. see http://www.galasoft.ch/mvvm */ using galasoft.mvvmlight; using galasoft.mvvmlight.ioc; using microsoft.practices.servicelocation; namespace mvvmlightdemo.viewmodel { /// <summary> /// this class contains static references to all the view models in the /// application and provides an entry point for the bindings. /// </summary> public class viewmodellocator { /// <summary> /// initializes a new instance of the viewmodellocator class. /// </summary> public viewmodellocator() { servicelocator.setlocatorprovider(() => simpleioc.default); #region code example ////if (viewmodelbase.isindesignmodestatic) ////{ //// // create design time view services and models //// simpleioc.default.register<idataservice, designdataservice>(); ////} ////else ////{ //// // create run time view services and models //// simpleioc.default.register<idataservice, dataservice>(); ////} #endregion simpleioc.default.register<mainviewmodel>(); } #region 实例化 public mainviewmodel main { get { return servicelocator.current.getinstance<mainviewmodel>(); } } #endregion public static void cleanup() { // todo clear the viewmodels } }
注意的是,这边把mvvmlight 自带的simpleioc作为默认的服务提供者,它是个简易的注入框架。
为了统一化,并且在设计的时候可以看到看到viewmodel的数据,这边用servicelocator 又将simpleioc包裹了一层。
上面我们写了一个hello world,这时候就可以用这种方式改装了。
/* in app.xaml: <application.resources> <vm:viewmodellocator xmlns:vm="clr-namespace:mvvmlightdemo" x:key="locator" /> </application.resources> in the view: datacontext="{binding source={staticresource locator}, path=viewmodelname}" you can also use blend to do all this with the tool's support. see http://www.galasoft.ch/mvvm */ using galasoft.mvvmlight; using galasoft.mvvmlight.ioc; using microsoft.practices.servicelocation; namespace mvvmlightdemo.viewmodel { /// <summary> /// this class contains static references to all the view models in the /// application and provides an entry point for the bindings. /// </summary> public class viewmodellocator { /// <summary> /// initializes a new instance of the viewmodellocator class. /// </summary> public viewmodellocator() { servicelocator.setlocatorprovider(() => simpleioc.default); #region code example ////if (viewmodelbase.isindesignmodestatic) ////{ //// // create design time view services and models //// simpleioc.default.register<idataservice, designdataservice>(); ////} ////else ////{ //// // create run time view services and models //// simpleioc.default.register<idataservice, dataservice>(); ////} #endregion simpleioc.default.register<mainviewmodel>(); simpleioc.default.register<welcomeviewmodel>(); } #region 实例化 public mainviewmodel main { get { return servicelocator.current.getinstance<mainviewmodel>(); } } public welcomeviewmodel welcome { get { return servicelocator.current.getinstance<welcomeviewmodel>(); } } #endregion public static void cleanup() { // todo clear the viewmodels } }
注册完welcomeviewmodel实例之后,我们就可以在相应的view中使用了 ,原本的
public welcomeview() { initializecomponent(); this.datacontext = new welcomeviewmodel(); }
中的 this.datacontext = new welcomeviewmodel();
可以去掉了,直接在welcomeview中这样写:
datacontext="{binding source={staticresource locator},path=welcome}"
如下图:
这样做的好处,一个是绑定化相对于简单粗暴的赋值方式,更合理。一个是在可视化窗口可以看到所绑定的数据,达到所见即所得的友好效果。
如下:
当我们改掉绑定到的数据,编译之后就会立马呈现:
服务端开发人员可以专心写viewmodel的业务逻辑代码,ui开发人员可以专注设计视图了,
同样 viewmodel可以绑定到不同的视图上,所以从这边就可以体现出他其中的三个重要特性:低耦合、可重用性、独立开发。
大家有没有发现viewmodellocator 类中还有个 clearnup()方法,主要目的用来清除viewmodel实例的。
viewmodelbase继承了galasoft.mvvmlight.icleanup接口,并在自己的类中写好了cleanup()虚方法。所以我们在实例viewmodel类中可以重写cleanup()来达到清除当前实例的目的。
以上就是mvvmlight 之model view结构及全局视图模型注入器的详细内容,更多关于viewmodel 结构及全局视图模型注入器的资料请关注其它相关文章!
上一篇: 数学建模-校赛-指纹识别
下一篇: C#基于Sockets类实现TCP通讯