• WPF快速入门系列(8)——MVVM快速入门


    一、引言

      在前面介绍了WPF一些核心的内容,其中包括WPF布局、依赖属性、路由事件、绑定、命令、资源样式和模板。然而,在WPF还衍生出了一种很好的编程框架,即WVVM,在Web端开发有MVC,在WPF客户端开发中有MVVM,其中VM就相当于MVC中C(Control)。在Web端,微软开发了Asp.net MVC这样的MVC框架,同样在WPF领域,微软也开发了Prism这样的MVVM框架。Prism项目地址是:http://compositewpf.codeplex.com/SourceControl/latest。大家有兴趣的可以下载源码研究下。

      本文所有源码下载:FristMVVMProject.zip

    二、MVVM模式是什么?

      既然讲到MVVM模式,自然第一个问题就是MVVM的含义。MVVM是Model-View-ViewModel的缩写形式,它通常被用于WPF或Silverlight开发。这三者之间的关系如下图所示:

      下面我们分别来介绍下这三部分。

    模型(Model)

      Model——可以理解为带有字段,属性的类。

    视图(View)

      View——可以理解为我们所看到的UI。

    视图模型(View Model)

    View Model在View和Model之间,起到连接的作用,并且使得View和Model层分离。View Model不仅仅是Model的包装,它还包含了程序逻辑,以及Model扩展,例如,如果Model中有一个公开属性不需要在UI上显示,此时我们可以不再View Model中去定义它。

    在MVVM模式下,WPF程序的运行流程如下图所示:

      在MVVM中,VM的地位可以说是举足轻重。使用MVVM模式具有以下几个特点:

    • 视图的cs文件包括极少的代码,其核心逻辑都被放在View Model类中,从而使得程序逻辑与视图耦合度降低。
    • ViewModel类作为View的DataContext。
    • 在MVVM下,所有的事件和动作都被当成命令,如按钮的点击操作,此时不是触发点击事件,而是绑定到一个点击命令,再由命令去执行对应的逻辑。

    三、使用MVVM模式来实现WPF程序

      前面介绍了MVVM一些基础知识,下面通过一个实例来说明下如何在WPF程序中应用MVVM模式。在之前实现WPF程序时,我们可能会把所有的后台逻辑都放在视图的后台文件中,这样的实现方式的好处更直观,方便,对于一些小的应用程序这样做当然没什么问题,但是对于复杂的应用程序这样写的话,可能会导致后台代码显得非常臃肿,到最好变得难以维护。此时想到的解决方案就是职责分离,使后台的逻辑分离到其他类中,MVVM其实我理解就是达到这个目的。下面我们按照MVVM的组成部分来实现下这个MVVM程序。

      第一步:自然是数据部分了,即Model层的实现。在这里定义了一个Person类,其中包含了2个基本的属性。

    public class Person
        {
            public string Name { get; set; }
            public int Age { get; set; }
        }

      为了进行测试,下面创建一个静态方法来获得测试数据。

    public class PersonDataHelper
        {
            public static ObservableCollection<Person> GetPersons()
            {
                ObservableCollection<Person> samplePersons = new ObservableCollection<Person>();
                samplePersons.Add(new Person() {Name = "张三", Age = 33});
                samplePersons.Add(new Person() { Name ="王五", Age= 22 });
                samplePersons.Add(new Person() { Name = "李四", Age = 35 });
                samplePersons.Add(new Person() { Name = "LearningHard", Age = 27 });
                return samplePersons;
            }
        }

      第二步:实现ViewModel层,实现数据和界面之间的逻辑。在视图模型类中,包含了属性和命令,因为在MVVM中,事件都当成命令来进行处理,其中命令只能与具有Command属性的控件进行绑定。既然要包含命令,首先就需要实现一个命令,这里自定义的命令需要实现ICommand接口。这里我们定义了一个QueryCommand。具体的实现代码如下所示:

    public class QueryCommand :ICommand
        {
            #region Fields
            private Action _execute;
            private Func<bool> _canExecute;
            #endregion 
    
            public QueryCommand(Action execute)
                : this(execute, null)
            { 
            }
            public QueryCommand(Action execute, Func<bool> canExecute)
            {
                if (execute == null)
                    throw new ArgumentNullException("execute");
                _execute = execute;
                _canExecute = canExecute;
            }
    
            #region ICommand Member
    
            public event EventHandler CanExecuteChanged
            {
                add
                {
                    if (_canExecute != null)
                    {
                        CommandManager.RequerySuggested += value;
    
                    }
                }
                remove
                {
                    if (_canExecute != null)
                    {
                        CommandManager.RequerySuggested -= value;
    
                    }
                }
            }
    
            public bool CanExecute(object parameter)
            {
                return _canExecute == null ? true : _canExecute();
            }
    
            public void Execute(object parameter)
            {
                _execute();
            }
            #endregion
        }

      接下来就是定义我们的ViewModel类了,具体的实现代码如下所示:

     1 public class PersonListViewModel : INotifyPropertyChanged
     2     {
     3         #region Fields
     4         private string _searchText;
     5         private ObservableCollection<Person> _resultList;
     6         #endregion 
     7 
     8         #region Properties
     9 
    10         public ObservableCollection<Person> PersonList { get; private set; }
    11 
    12         // 查询关键字
    13         public string SearchText
    14         {
    15             get { return _searchText; }
    16             set
    17             {
    18                 _searchText = value;
    19                 RaisePropertyChanged("SearchText");
    20             }
    21         }
    22 
    23         // 查询结果
    24         public ObservableCollection<Person> ResultList
    25         {
    26             get { return _resultList; }
    27             set
    28             {
    29                 _resultList = value;
    30                 RaisePropertyChanged("ResultList");
    31             }
    32         }
    33 
    34         public ICommand QueryCommand 
    35         { 
    36             get { return new QueryCommand(Searching, CanSearching); } 
    37         }
    38 
    39         #endregion 
    40 
    41         #region Construction
    42         public PersonListViewModel()
    43         {
    44             PersonList = PersonDataHelper.GetPersons();
    45             _resultList = PersonList;
    46         }
    47 
    48         #endregion
    49         
    50         #region Command Handler
    51         public void Searching()
    52         {
    53             ObservableCollection<Person> personList = null;
    54             if (string.IsNullOrWhiteSpace(SearchText))
    55             {
    56                 ResultList = PersonList;
    57             }
    58             else
    59             {
    60                 personList = new ObservableCollection<Person>();
    61                 foreach (Person p in PersonList)
    62                 {
    63                     if (p.Name.Contains(SearchText))
    64                     {
    65                         personList.Add(p);
    66                     }
    67                 }
    68                 if (personList != null)
    69                 {
    70                     ResultList = personList;
    71                 }
    72             }
    73         }
    74 
    75         public bool CanSearching()
    76         {
    77             return true;
    78         }
    79 
    80         #endregion 
    81 
    82         #region INotifyPropertyChanged Members
    83 
    84         public event PropertyChangedEventHandler PropertyChanged;
    85 
    86         #endregion
    87 
    88         #region Methods
    89         private void RaisePropertyChanged(string propertyName)
    90         {
    91             // take a copy to prevent thread issues
    92             PropertyChangedEventHandler handler = PropertyChanged;
    93             if (handler != null)
    94             {
    95                 handler(this, new PropertyChangedEventArgs(propertyName));
    96             }
    97         }
    98         #endregion 
    99     }

      第三步:实现View层,设计我们的视图,设置它的DataContext属性为ViewModel类。具体的XAML代码如下所示:

    <Window x:Class="MVVMDemo.View.PersonsView"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:MVVMDemo.ViewModel"
            Title="PersonsView" Height="350" Width="400">
        <!--设置DataContex是ViewModel类,当然你也可以使用后台代码设置-->
        <Window.DataContext>
            <local:PersonListViewModel />
        </Window.DataContext>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="50"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <TextBox Grid.Row="0" Name="searchtxt" Text="{Binding  Path=SearchText, Mode=TwoWay}" HorizontalAlignment="Left" Height="30" Width="280" Margin="10,0,0,0"></TextBox>
            <Button Grid.Row="0" Name="searchBtn" Content="Search" Command="{Binding Path=QueryCommand}" Width="80" Height="30" HorizontalAlignment="Right" Margin="0,0,10,0"></Button>
            <DataGrid Grid.Row="1" Name="datGrid" 
                      HorizontalAlignment="Center"
                      VerticalAlignment="Top" ItemsSource="{Binding Path=ResultList}" Width="300"></DataGrid>
            
        </Grid>
    </Window>

      到此,我们的MVVM的WPF程序就已经完成了,下面就是要看看程序是否达到我们预期的目的。具体的运行结果如下图所示:

    四、总结

      到这里,本文的内容就分享完了,并且本文也是WPF系列的最后一篇了,希望这个系列可以使得初学者快速上手WPF编程。在接下来的时间里,我打算写一些具有实战性的内容,因为我之前都是分享一些初级的入门系列,接下来打算分享一些实际的项目实现,以及领域驱动设计方面的内容,希望得到大家的督促和支持。

     

  • 相关阅读:
    vmware centos 共赏目录不显示
    小程序上拉刷新
    chrome json接口数据 插件
    滚动条滚动事件
    smarty循环item命名规范
    css实现梯形样式(含有border)
    设置行高并不能垂直居中
    图片翻转交互效果
    smarty文章字符截取
    css动画 transition
  • 原文地址:https://www.cnblogs.com/zhili/p/MVVMDemo.html
Copyright © 2020-2023  润新知