欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

MVVMLight项目Model View结构及全局视图模型注入器

程序员文章站 2022-03-01 13:28:57
目录一、先来说说分层结构:1、写一个model,代码如下:2、写一个videmodel,来负责跟view的交互。3、写一个view,来显示和交互viewmodel。二、再来说说构造器:mvvm和mvv...

mvvm和mvvmlight框架介绍及在项目中的使用详解

上一篇我们已经介绍了如何使用nuget把mvvmlight应用到我们的wpf项目中。这篇我们来了解下一个基本的mvvmlight框架所必须的结构和运行模式。

mvvmlight安装之后,我们可以看到简易的框架布局,如上篇,生成了一个viewmodel文件夹,viewmodel层的内容都放在这边,除了main对象的viewmodel之外,还包含一个viewmodellocator文件,

用来注入当前的viewmodel全局实例。

一、先来说说分层结构:

MVVMLight项目Model View结构及全局视图模型注入器

如图:

1、view负责前端展示,与viewmodel进行数据和命令的交互。

2、viewmodel,负责前端视图业务级别的逻辑结构组织,并将其反馈给前端。

3、model,主要负责数据实体的结构处理,与viewmodel进行交互。

根据上述的分层,我们来进行编码。

先建立一个完整三层结构的目录,如图,包含model、view、viewmodel三层文件夹:

MVVMLight项目Model View结构及全局视图模型注入器

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中所有的公开属性和命令。

执行效果如下:

MVVMLight项目Model View结构及全局视图模型注入器

二、再来说说构造器:

如果使用nuget安装的是完整的一个是mvvm light 框架,而非 mvvm light libraries only的时候,总是会带上viewmodellocator类,并且生成资源字典并加入到了全局资源中。

MVVMLight项目Model View结构及全局视图模型注入器

<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}"

如下图:

MVVMLight项目Model View结构及全局视图模型注入器

这样做的好处,一个是绑定化相对于简单粗暴的赋值方式,更合理。一个是在可视化窗口可以看到所绑定的数据,达到所见即所得的友好效果。

如下:

MVVMLight项目Model View结构及全局视图模型注入器

当我们改掉绑定到的数据,编译之后就会立马呈现:

MVVMLight项目Model View结构及全局视图模型注入器

服务端开发人员可以专心写viewmodel的业务逻辑代码,ui开发人员可以专注设计视图了,

同样 viewmodel可以绑定到不同的视图上,所以从这边就可以体现出他其中的三个重要特性:低耦合、可重用性、独立开发。

大家有没有发现viewmodellocator 类中还有个 clearnup()方法,主要目的用来清除viewmodel实例的。

viewmodelbase继承了galasoft.mvvmlight.icleanup接口,并在自己的类中写好了cleanup()虚方法。所以我们在实例viewmodel类中可以重写cleanup()来达到清除当前实例的目的。

以上就是mvvmlight 之model view结构及全局视图模型注入器的详细内容,更多关于viewmodel 结构及全局视图模型注入器的资料请关注其它相关文章!