MVVM开发模式简单实例MVVM Demo

本文主要是翻译Rachel Lim的一篇有关MVVM模式介绍的博文 A Simple MVVM Example

并具体给出了一个简单的Demo(原文是以WPF开发的,对于我自己添加的一部分会用红色标注)

现在开始:

在我看来,如果你使用的是WPF或Sliverlight来开发程序就应该使用MVVM设计模式。它是你的代码清晰明了并易于维护。

可问题是网上有很多有关MVVM模式的资源都有自己强大的实现方式。这里我将介绍最基础的MVVM设计模式的实现方法。

MVVM  (是Model-View-ViewModel的缩写)

Model: 保存数据的简单类对象,它只能包含属性和属性验证(应该就是验证属性值是否正确),而不负责存储数据、事件点击、复杂运算、业务规则和其他操作。

View: 呈现给用户的数据界面,很多情况下,他是以数据模板(DataTemplates)的方式告诉应用如何呈现类中内容的。

      如果代码内容只跟View有关(比如社交焦点和执行动画),可以将代码写在View的后台。

ViewModel:用来处理逻辑。你的后台代码(数据访问、点击事件、复杂运算、业务规则验证等)都写在这里。这里面的代码View的反应。

比如,View中有一个ListBox对象、选中的对象、保存按钮。ViewModel中就要包含ObservableCollection<Model>集合、

Mode类型的SelectedObject和命令ICommand SaveCommand.

下面就通过一个简单的例子看看这三者之间是如何相互联系的。你会发现除了属性和方法名,任意一者是不需要访问另外两者的。

一旦接口被定义了,每一层可以完全独立于其他运行。

此例中,我使用的是Product Model,这个类中只含有属性和属性更改通知(INotifyPropertyChanged)

1.Model

public class ProductModel : ViewModelBase
    {
        //字段
        private int _productId;
        private string _productName;
        private decimal _unitPrice;

        //属性
        public int ProductId
        {
            get { return _productId; }
            set
            {
                SetProperty(ref this._productId, value);
            }
        }

        public string ProductName
        {
            get { return _productName; }
            set
            {
                SetProperty(ref this._productName, value);
            }
        }

        public decimal UnitPrice
        {
            get { return _unitPrice; }
            set
            {
                SetProperty(ref this._unitPrice, value);
            }
        }

        public ProductModel()
        {
            this.ProductName = "000000";
            this.ProductId = 111111;
            this.UnitPrice = 222222;
        }
    }

ProductModel继承了ViewModelBase类,而ViewModelBase实现了INotifyPropertyChanged接口

(ViewModelBase和原文不一样,只是简化了一下,具体可以查看 INotifyPropertyChanged接口的实现,介绍的很详细)

public class ViewModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public bool SetProperty<T>(ref T storage, T value, [CallerMemberName]string propertyName = null)
        {
            if (object.Equals(storage, value)) return false;
            storage = value;
            this.OnPropertyChanged(propertyName);
            return true;
        }

        protected void OnPropertyChanged([CallerMemberName]string propertyName = null)
        {
            var eventHandler = this.PropertyChanged;
            if (null != eventHandler)
            {
                eventHandler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

注意:属性更改通知(INotifyPropertyChanged):当Model中属性更改时,会通知View实时的更新View页面。

有人建议将这个放入ViewModel而不是Model中。虽然两种方式都是有效的,但是我发现放入ViewModel更加复杂,

还需要更多的代码。而放入Model中更简单些。

2.ViewModel
由于在创建View之前需要ViewModel,接下来我们就来创建ViewModel。它要包括用户操作所有的交互。

现在这里包括4个属性:CurrentProduct当前产品, 产品获取命令GetProductCommand,保存命令SaveProductCommand.用来查找某个产品的ProductId

public class ProductViewModel : ViewModelBase 
    {private int _productId;  
        private ProductModel _currentProduct;
        private ICommand _getProductCommand;
        private ICommand _saveProductCommand;public int ProductId
        {
            get { return _productId; }
            set
            {
                SetProperty(ref this._productId, value);
            }
        }
    public ProductViewModel()    {            CurrentProduct = new ProductModel();    }
        public ProductModel CurrentProduct
        {
            get { return _currentProduct; }
            set
            {
                if (null == _currentProduct)
                    _currentProduct = new ProductModel();
                _currentProduct = value;
            }
        }public ICommand SaveProductCommand
        {
            get
            {
                if (_saveProductCommand == null)
                {
                    _saveProductCommand = new RelayCommand(SaveProduct);
                }
                return _saveProductCommand;
            }
        }

        public ICommand GetProductCommand
        {
            get
            {
                if (_getProductCommand == null)
                    _getProductCommand = new RelayCommand(GetProduct, IsEnable);
                return _getProductCommand;
            }
        }public bool IsEnable()  //此控件是否可点击
        {
            return true;
        }

        public void SaveProduct()  //执行命令
        {
            await new MessageDialog("保存").ShowAsync();
        }

     public void GetProduct(object parameter)  //public void GetProduct(object parameter)        {            if (parameter.ToString() == string.Empty)                return;            ProductId = int.Parse(parameter.ToString());            ProductModel product = new ProductModel();            product.ProductName = "Test Product";            product.ProductId = ProductId;            product.UnitPrice = 10.00M;            CurrentProduct = product;        }
  }

这里出现了一个新类RelayCommand,MVVM的正常使用必不可少。这个命令表示的是由其他类调用委托来实现此类中的代码

[在建立非空项目的时候Command文件夹会自动那个生成此类,但是本身只定义了不带参数的方法,需要进行扩展---注释部分]

public class RelayCommand : ICommand
    {
        private readonly Action _execute;
        private readonly Func<bool> _canExecute;
        private readonly Action<object> _executeParam;  //新增了一个带参数有返回值的方法

        public event EventHandler CanExecuteChanged;

        public RelayCommand(Action execute)
            : this(execute, null)
        {
        }

        public RelayCommand(Action execute, Func<bool> canExecute)
        {
            if (execute == null)
                throw new ArgumentNullException("execute");
            _execute = execute;
            _canExecute = canExecute;
        }

        public RelayCommand(Action<object> executeParam)  //新增重载构造函数
        {
            if(executeParam == null)
                throw new ArgumentNullException("executeParam");
            _executeParam = executeParam;
            _canExecute = () => true;
        }

        public RelayCommand(Action<object> executeParam, Func<bool> canExecute)  //新增重载构造函数
        {
            if (executeParam == null)
                throw new ArgumentNullException("executeParam");
            _executeParam = executeParam;
            _canExecute = canExecute;
        }
        public bool CanExecute(object parameter)
        {
            return _canExecute == null ? true : _canExecute();
        }
        public void Execute(object parameter)  //新增判断
        {
            if (parameter == null)
                _execute();
            else
                _executeParam(parameter);
        }
        public void RaiseCanExecuteChanged()
        {
            var handler = CanExecuteChanged;
            if (handler != null)
            {
                handler(this, EventArgs.Empty);
            }
        }
    }

3.View(可以认为是MainPage.xaml)

<StackPanel>
  <StackPanel x:Name="stackpaenl1">
    <TextBlock Text="{Binding CurrentProduct.ProductId}" Foreground="Yellow"/>
    <TextBlock Text="{Binding CurrentProduct.ProductName}"/>
    <TextBlock Text="{Binding CurrentProduct.UnitPrice}"/>

    <TextBlock Text="Enter Product Id"/>    <TextBox x:Name="Input"/>    <TextBlock Text="{Binding ProductId}" Foreground="Yellow"/>
    <Button Content="Get Product" Command="{Binding GetProductCommand}" CommandParameter="{Binding ElementName=Input, Path=Text}"/>
    <Button Content="Save Product" Command="{Binding SaveProductCommand}"/>
  </StackPanel>
</StackPanel>

最后在View.cs添加代码

  ProductViewModel product = new ProductViewModel();
  product.ProductId = 111;
  this.DataContext = product;  //绑定错了的话   COMMAND是不会起作用的

以上就是简单的MVVM程序。

PS:下篇文章会接着本文

1.将添加Product集合,绑定到列表

2.给点击ListBox点击添加点击事件(要附加依赖属性,和Button点击事件不同)

3.通过自定义类以JSON获取保存数据到存储空间

时间: 2024-12-29 23:52:32

MVVM开发模式简单实例MVVM Demo的相关文章

MVVM开发模式简单实例MVVM Demo【续】

本文将接着上篇文章,介绍一下三点:(Universal App) 1.将添加Product集合,绑定到列表 2.给点击ListBox的添加选项改变时的事件(要附加依赖属性,和Button点击事件不同) 3.通过自定义类以JSON获取保存数据到存储空间 ------------------------------------------------- 1.添加集合,绑定列表,支持可操作 在ProductViewModel中添加字段.属性: private ObservableCollection<

js架构设计模式——理解javascript中的MVVM开发模式

理解javascript中的MVVM开发模式 http://blog.csdn.net/slalx/article/details/7856769 MVVM的全称是Model View ViewModel,这种架构模式最初是由微软的MartinFowler作为微软软件的展现层设计模式的规范提出,它是MVC模式的衍生物,MVVM模式的关注点在能够支持事件驱动的UI开发平台,例如HTML5,[2][3] WindowsPresentation Foundation (WPF), Silverligh

android MVVM开发模式(一)

android MVVM开发模式 概念 mvvm 是一个在 mvp 架构上修改,目标是将view的一些更改,跟model关联起来,使得model的数据改变,直接通知到view上面来,从而解决mvp架构里面的v-p之间的接口太重问题. 所以mvvm的核心解决问题为:使得v-p直接的关系弱化,使用绑定方式(dataBinding)直接将model的改变反馈到view上面. 关于完整的dataBinding讲解,请看这里 https://github.com/LyndonChin/MasteringA

转 。。理解javascript中的MVVM开发模式

MVVM的全称是Model View ViewModel,这种架构模式最初是由微软的MartinFowler作为微软软件的展现层设计模式的规范提出,它是MVC模式的衍生物,MVVM模式的关注点在能够支持事件驱动的UI开发平台,例如HTML5,[2][3] WindowsPresentation Foundation (WPF), Silverlight 和 t ZK framework,Adobe Flex. 对这种模式的实现,大部分都是通过在view层声明数据绑定来和其他层分离的,这样就方便了

【SSH进阶之路】Hiberante3搭建开发环境+简单实例(二)

Hibernate是非常典型的持久层框架,持久化的思想是非常值得我们学习和研究的.这篇博文,我们主要以实例的形式学习Hibernate,不深究Hibernate的思想和原理,否则,一味追求,苦学思想和原理,到最后可能什么也学不会,从实践入手,熟能生巧,思想和原理自然而然领悟. 上篇博文:[SSH进阶之路]Hibernate基本原理,我们介绍了Hibernate的基本概念.Hibernate的核心以及Hibernate的执行原理,可以很好帮助我们认识Hibernate,再看这篇博客之前,请先回顾上

java 工厂方法模式简单实例

工厂方法模式:也叫工厂模式,属于类创建型模式,工厂父类(接口)负责定义产品对象的公共接口,而子类工厂则负责创建具体的产品对象. 目的:是为了把产品的实例化操作延迟到子类工厂中完成,通过工厂子类来决定究竟应该实例化哪一个产品具体对象. 工厂方法模式包含四个部分: 1.抽象产品:产品对象同一的基类,或者是同一的接口. 2.具体的产品:各个不同的实例对象类 3.抽象工厂:所有的子类工厂类的基类,或是同一的接口 4.具体的工厂子类:负责每个不同的产品对象的实际创建 具体的实例代码: 1.抽象的产品类:定

VS2008中C#开发webservice简单实例

1.创建工程 文件-> 新建->网站 如下图. 工程建好后,会自动添加如下代码: 1 using System; 2 using System.Linq; 3 using System.Web; 4 using System.Web.Services; 5 using System.Web.Services.Protocols; 6 using System.Xml.Linq; 7 8 [WebService(Namespace = "http://tempuri.org/"

MTV开发模式简单说明

Django的MTV模式本质上和MVC是一样,越是为了各组件件保持松耦合关系,只是定义上有些不同Django的MTV分别是:M代表模型(Model):负责业务对象和数据库的关系映射(ORM)T代表模块(Template):负责如何把页面展示给用户(html)V代表视图(View):负责业务逻辑,并在适合的时候调用Model和Template处理以上三层之外,还需要一个URL分发器,她它的作用是将一个个的URL页面请求分发给不同的Views处理,View再调用相应的Model和Template,M

不用IDE,进行struts2开发的简单实例

1.在tomcat的webapp中创建一个WEB工程myapp,具体的文件及路径如下所示: ①/webapp/myapp/login.jsp ②/webapp/myapp/welcom.jsp ③/webapp/myapp/error.jsp ④/webapp/myapp/WEB-INF/web.xml ⑤/webapp/myapp/WEB-INF/classes ⑥/webapp/myapp/WEB-INF/classes/struts.xml ⑦/webapp/myapp/WEB-INF/c