MVVM(Model-View-ViewModel)实例讲解

    技术2022-05-19  22

    MVVM(Model-View-ViewModel)实例讲解

    2009年12月31日 分类: Silverlight, WPF

    MVVM模式大家应该不陌生吧,陌生的快来看看,可是WPF/Silverlight开发中,必备的设计模式。MVVM模式解决了,我们在开发WPF/Silverlight应用程序过程中产生的业务层、表示层比较混乱问题,使表示层和业务层完全分离。早在2005年,John Gossman写了一篇关于Model-View-ViewModel模式的博文,这种模式被他所在的微软的项目组用来创建Expression Blend。

    从上图可以看出来,View表示层就是我们通常的XAML,用来表示前台界面,ViewModel视图模块层的作用用来连接业务逻辑和视图层的关键部分,通常我们发出的命令或者事件都是通过这层传送给业务逻辑层的,Model就是我们的实际数据,业务逻辑代码等。

    下面我们用一个Silverlight简单例子来讲解MVVM模式

    这个程序就是实现简单查询,输入ID号,查询符合结果的内容

    新建一个Silverlight项目,并按照下图新建目录

    Command我们用来存放查询用的命令,Model我们用来存放数据,View我们用来存放显示查询的UserControl,ViewModel我们用来存放查询的ViewModel

    我们先建立Model层用来存储访问要查询的数据

    1 2 3 4 5 6 public class DataItem {      public int ID { get ; set ; }      public string Name { get ; set ; } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public static class DataDemo {      private static Collection<DataItem> _DataList = null ;         public static Collection<DataItem> DataList      {          get          {              if (_DataList == null )              {                  _DataList = InitDataList();              }              return _DataList;          }      }         private static Collection<DataItem> InitDataList()      {          Collection<DataItem> lists = new Collection<DataItem>();          for ( int i = 0; i < 100; i++)          {              DataItem item = new DataItem();              item.ID = i + 1;              item.Name = "例子" + (i + 1);              lists.Add(item);          }          return lists;      } }

    接下来,我们新建UserControl用来表示查询的页面(View)

    1 2 3 4 5 6 7 8 9 10 11 12 < UserControl x:Class = "MVVMDemo.View.QueryData"   xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"   xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"   xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006"   xmlns:local = "clr-namespace:MVVMDemo.ViewModel"   mc:Ignorable = "d" Height = "256" Width = "256" >      < Grid x:Name = "LayoutRoot" >          < Button x:Name = "btnSearch" Height = "24" HorizontalAlignment = "Left" Margin = "164,8,0,0" VerticalAlignment = "Top" Width = "84" Content = "搜索" />          < TextBox x:Name = "txtKeyword" Height = "24" HorizontalAlignment = "Left" Margin = "8,8,0,0" VerticalAlignment = "Top" Width = "152" TextWrapping = "Wrap" d:LayoutOverrides = "HorizontalAlignment" />          < TextBox x:Name = "txtResult" HorizontalAlignment = "Left" Margin = "8,36,0,8" Width = "240" TextWrapping = "Wrap" d:LayoutOverrides = "VerticalAlignment" />      </ Grid > </ UserControl >

    到这里我们已经建好了Model,View层,接下来,我们建立ViewModel

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 public class QueryDataViewModel : INotifyPropertyChanged {      #region 变量      /// <summary>      /// 查询的数据      /// </summary>      private Collection<DataItem> _DataList = null ;      /// <summary>      /// 查询命令      /// </summary>      private ICommand _QueryCommand = null ;      /// <summary>      /// 搜索关键字      /// </summary>      private string _SearchText = string .Empty;      /// <summary>      /// 搜索结果      /// </summary>      private string _SearchResult = string .Empty;      #endregion         #region 属性      /// <summary>      /// 搜索关键字      /// </summary>      public string SearchText      {          get { return this ._SearchText; }          set          {              this ._SearchText = value;              if ( this .PropertyChanged != null )                  this .PropertyChanged( this , new PropertyChangedEventArgs( "SearchText" ));          }      }      /// <summary>      /// 搜索结果      /// </summary>      public string SearchResult      {          get { return this ._SearchResult; }          set          {              this ._SearchResult = value;                 if ( this .PropertyChanged != null )                  this .PropertyChanged( this , new PropertyChangedEventArgs( "SearchResult" ));          }      }      /// <summary>      /// 查询命令      /// </summary>      public ICommand QueryCommand      {          get { return _QueryCommand; }      }      #endregion         #region 构造函数      public QueryDataViewModel(Collection<DataItem> dataList)      {          this ._DataList = dataList;          _QueryCommand = new QueryDataCommand( this );      }      #endregion         #region 方法      /// <summary>      /// 查询数据      /// </summary>      public void QueryData()      {          if (! string .IsNullOrEmpty( this .SearchText))          {              DataItem dataItem = null ;              foreach (DataItem item in this ._DataList)              {                  if (item.ID.ToString() == this .SearchText)                  {                      dataItem = item;                      break ;                  }              }              if (dataItem != null )              {                  this .SearchResult = string .Format( "ID:{0}/nName:{1}" , dataItem.ID, dataItem.Name);              }          }      }      #endregion         #region INotifyPropertyChanged 成员         public event PropertyChangedEventHandler PropertyChanged;         #endregion }

    这是一个很简单的ViewModel,我们定义了两个属性,SearchText表示查询关键字,SearchResult表示查询结果,QueryCommand表示查询命令,后面我们会和View绑定。QueryDataCommand还没有实现,接下来我们创建QueryCommand

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public class QueryDataCommand : ICommand {      private QueryDataViewModel _QueryDataViewModel;         public QueryDataCommand(QueryDataViewModel queryDataViewModel)      {          this ._QueryDataViewModel = queryDataViewModel;      }         #region ICommand 成员         public bool CanExecute( object parameter)      {          return true ;      }         public event EventHandler CanExecuteChanged      {          add { }          remove { }      }         public void Execute( object parameter)      {          this ._QueryDataViewModel.QueryData();      }         #endregion }

    到目前为止,ViewModel已经建立完成。我们将ViewModel绑定到ViewView的代码

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 public partial class QueryData : UserControl {      private QueryDataViewModel _QueryDataViewModel = null ;         /// <summary>      /// 构造函数      /// </summary>      public QueryData()      {          InitializeComponent();             this ._QueryDataViewModel = new QueryDataViewModel(MVVMDemo.DataDemo.DataList);          base .DataContext = this ._QueryDataViewModel;          this .btnSearch.Click += new RoutedEventHandler(btnSearch_Click);      }         /// <summary>      /// 点击事件      /// </summary>      /// <param name="sender"></param>      /// <param name="e"></param>      void btnSearch_Click( object sender, RoutedEventArgs e)      {          if ( this ._QueryDataViewModel != null )          {              this ._QueryDataViewModel.SearchText = this .txtKeyword.Text;              this ._QueryDataViewModel.QueryCommand.Execute( null );          }      } }

    因为Silverlight没有Command,我们只能采用这个方法调用Command,wpf则可以在xaml里面直接绑定这个命令前台xaml我们把输入框,后结果框绑定输入框

    1 2 输入框 Text="{Binding SearchText,Mode=TwoWay}" 结果框 Text="{Binding SearchResult,Mode=OneWay}"

    我们把View放到页面上

    1 2 3 4 5 6 7 8 9 10 < UserControl x:Class = "MVVMDemo.MainPage"   xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"   xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"   xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006"   xmlns:local = "clr-namespace:MVVMDemo.View"   mc:Ignorable = "d" Height = "256" Width = "256" >      < Grid >          < local:QueryData ></ local:QueryData >      </ Grid > </ UserControl >

    到目前为止,MVVM最简单的例子已经建立完成。我们发现表示层和业务逻辑层从此实现了分离,同时,我们在单元测试上也可以剥离表示层进行。

    原创文章,转载请注明: 转载自.NET开发者

    本文链接地址: MVVM(Model-View-ViewModel)实例讲解

     

    ShareThis


    最新回复(0)