当前位置: 首页 > 图灵资讯 > 技术篇> WPF快速入门系列(8)——MVVM快速入门

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

来源:图灵教育
时间:2023-06-06 09:27:04

一、引言

  WPF的一些核心内容,包括WPF布局、依赖属性、路由事件、绑定、命令、资源风格和模板。然而,WPF也衍生出一个很好的编程框架,即WVVM,在Web端开发MVC,在WPF客户端开发MVVM,其中VM相当于MVC(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 在View和Model之间,Model起着连接作用,使View和Model层分离。View Model不仅是Model的包装,还包括程序逻辑和Model的扩展。例如,如果Model中有一个不需要显示在UI上的公共属性,我们就不能再view了 在Model中定义它。

WPF程序的运行流程如下图所示:

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

  VM在MVM中的地位可以说是非常重要的。MVVM模式的使用具有以下特点:

  • 视图中的cs文件包含很少的代码,其核心逻辑被放置在Vieww 在Model类中,程序逻辑和视图耦合度降低。
  • 作为View的Datacontext,ViewModel类。
  • 在MVVM下,所有的事件和动作都被视为命令,比如按钮的点击。此时,它不是触发点击事件,而是绑定到点击命令中,然后命令执行相应的逻辑。
使用MVVM模式实现WPF程序

  本文介绍了MVVM的一些基本知识,以下是如何在WPF程序中应用MVVM模式的例子。在实现WPF程序之前,我们可能会把所有的背景逻辑放在视图背景文件中,这种实现的好处更直观、方便,对于一些小应用程序当然没有问题,但对于复杂的应用程序,可能会导致背景代码非常臃肿,最好变得难以维护。在这个时候,我想到的解决方案是分离责任,将后台的逻辑分离到其他类别。事实上,我理解MVVM就是为了实现这一目标。下面我们将根据MVVM的组成部分来实现这个MVVM程序。

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

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接口。在这里,我们定义了一个QueryComand。具体实现代码如下:

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 Searchtextt144         {15             get { return _searchText; }16             set17             {18                 _searchText = value;19                 RaisePropertyChanged("SearchText");20             }21         }22 23         // 查询结果24         public ObservableCollection<Person> Resultlist25         {26             get { return _resultList; }27             set28             {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         public PersonListViewModel()43         {44             PersonList = PersonDataHelper.GetPersons();45             _resultList = PersonList;46         }47 48         #endregion49         50         #region Command Handler51         public void Searching()52         {53             ObservableCollection<Person> personList = null;54             if (string.IsNullOrWhiteSpace(SearchText))55             {56                 ResultList = PersonList;57             }58             else59             {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 Members83 84         public event PropertyChangedEventHandler PropertyChanged;85 86         #endregion87 88         #region Methods89         private void RaisePropertyChanged(string propertyName)90         {91             // take a copy to prevent thread issues92             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>

  到目前为止,我们的MVVMWPF程序已经完成,这取决于程序是否达到了我们的预期目的。具体操作结果如下图所示:

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

四、总结

  在这里,本文的内容被分享,本文也是WPF系列的最后一篇文章。我希望这个系列能让初学者快速开始WPF编程。在接下来的时间里,我计划写一些实用的内容,因为我以前分享一些初级入门系列,然后我计划分享一些实际的项目实现和领域驱动设计,我希望得到每个人的监督和支持。