MVVM的基本流程:
- 在项目中分别新建Model,View,ViewModel,Command四个文件夹。
- Model:存放数据新建的类
- View:存放视图.xaml文件
- ViewModel 准备对应界面的数据与一些业务,主要包括数据,命令,此处的数据也需要能PropertyChanged通知。
- 自定义的一些命令
- 准备Model的数据,该自定义类需要继承自INotifyPropertyChanged
- 例如:
namespace eventDemo.Model { public class Employee:INotifyPropertyChanged { int _employeeNumber; string _firstName; string _lastName; string _department; string _title; public Employee() { _employeeNumber = 0; _firstName = _lastName = _department = _title = null; } public int EmployeeNumber { get { return _employeeNumber; } set { _employeeNumber = value; OnPropertyChanged("EmployeeNumber"); } } public string FirstName { get { return _firstName; } set { _firstName = value; OnPropertyChanged("FirstName"); } } public string LastName { get { return _lastName; } set { _lastName = value; OnPropertyChanged("LastName"); } } public string Department { get { return _department; } set { _department = value; OnPropertyChanged("Department"); } } public string Title { get { return _title; } set { _title = value; OnPropertyChanged("Title"); } } public override string ToString() { return String.Format("{0} {1} ({2})", FirstName, LastName, EmployeeNumber); } protected void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChangedEventArgs args = new PropertyChangedEventArgs(propertyName); this.PropertyChanged(this, args); } } #region INotifyPropertyChanged Members public event PropertyChangedEventHandler PropertyChanged; #endregion } }
- 例如:
- 在Command中添加自定义Command类,该类需要继承自 ICommand,再应用以下模版之后,还需要在ViewModel中,定义ExecuteAction(要执行的方法)与CanExecuteAction(能否执行,一般直接返回True)
- 例如:
public class CustomCommand : ICommand { //当能不能做发生变化时会触发的事件(必须要实现) public event EventHandler CanExecuteChanged; public void Execute(object param) //做什么(必须要实现) { ExecuteAction?.Invoke(param); } public bool CanExecute(object param) //能做吗(必须要实现) { if (CanExecuteAction != null) return CanExecuteAction(param); return false; } //Action可以放一个函数进去,就是命令执行的动作 public Action<object> ExecuteAction { get; set; } public Func<object, bool> CanExecuteAction { get; set; } } 在ViewModel中设置 例如: //准备命令 public CustomCommand MyCommand { get; set; } MyCommand = new CustomCommand(); //完成命令动作的设置,两个都要设置 MyCommand.ExecuteAction = new Action<object>(Excute); MyCommand.CanExecuteAction = new Func<object, bool>(this.CanExcute); public void Excute(object employee) //自定义的动作方法 { SelectedEmployee = (Employee)employee; } public bool CanExcute(object param) { return true; //判断能否做这个事情,大部分时候返回true就行了 } 完成ViewModel文件中的 数据 命令 初始化,因为VeiwModel也要维护属性,需要自动通知,所以也要继承自继承自INotifyPropertyChanged 代码: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using eventDemo.Model; using System.ComponentModel; using eventDemo.Common; namespace eventDemo.viewModel { public class MainWindowViewModel:INotifyPropertyChanged { public List<Employee> empList { get; set; } //准备数据 private Employee selectedEmployee; public Employee SelectedEmployee { get { return selectedEmployee; } set { selectedEmployee = value; //事件导致的对象数据变化 NotifyPropertyChanged("SelectedEmployee");//这里填写改变的数据的名字string } } //准备命令 public CustomCommand MyCommand { get; set; } //ViewModel文件初始化 public MainWindowViewModel() { //初始化数据 List<Employee> elist = new List<Employee>(); elist.Add(new Employee() { EmployeeNumber = 1, FirstName = "John", LastName = "Dow", Title = "Accountant", Department = "Payroll" }); elist.Add(new Employee() { EmployeeNumber = 2, FirstName = "Jane", LastName = "Austin", Title = "Account Executive", Department = "Employee Management" }); elist.Add(new Employee() { EmployeeNumber = 3, FirstName = "Ralph", LastName = "Emmerson", Title = "QA Manager", Department = "Product Development" }); elist.Add(new Employee() { EmployeeNumber = 4, FirstName = "Patrick", LastName = "Fitzgerald", Title = "QA Manager", Department = "Product Development" }); elist.Add(new Employee() { EmployeeNumber = 5, FirstName = "Charles", LastName = "Dickens", Title = "QA Manager", Department = "Product Development" }); empList = elist; //初始化命令 MyCommand = new CustomCommand(); //完成命令动作的设置 MyCommand.ExecuteAction = new Action<object>(Excute); MyCommand.CanExecuteAction = new Func<object, bool>(this.CanExcute); } public void Excute(object employee) { SelectedEmployee = (Employee)employee; } public bool CanExcute(object param) { return true; //判断能否做这个事情,大部分时候返回true就行了 } protected void NotifyPropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChangedEventArgs args = new PropertyChangedEventArgs(propertyName); this.PropertyChanged(this, args); } } //准备事件管理器 public event PropertyChangedEventHandler PropertyChanged; } }
- 例如:
- 完成后端业务与View的连接,ViewModel中有数据,命令,可以理解为规定了数据与动作,但是实际需要操作View的业务,所以需要将View与ViewModel建立联系。
- 在xaml文件中设置binding实现业务,在这里需要学习bingding,Trigger,DataTemplate,自定义控件(Style ControlTemplate等WPF Ui相关的知识)
- 代码(注意其中的binding)
<Window x:Class="eventDemo.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:i="http://schemas.microsoft.com/xaml/behaviors" xmlns:vm="clr-namespace:eventDemo.viewModel" Title="MainWindow" Height="250" Width="300" MinHeight="200"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="110px" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <ListBox Name="employeeListBox" ItemsSource="{Binding empList}" Grid.Row="0" SelectedItem="{Binding SelectedEmployee, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"> <i:Interaction.Triggers> <i:EventTrigger EventName="SelectionChanged"> <i:InvokeCommandAction Command="{Binding MyCommand}" CommandParameter="{Binding ElementName=employeeListBox, Path=SelectedItem}"/> </i:EventTrigger> </i:Interaction.Triggers> </ListBox> <Grid Grid.Row="1" DataContext="{Binding SelectedEmployee}"> <Grid.RowDefinitions> <RowDefinition Height="*" /> <RowDefinition Height="*" /> <RowDefinition Height="*" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="80" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Label Grid.Row="0" Grid.Column="0">First Name</Label> <Label Grid.Row="1" Grid.Column="0">Last Name</Label> <Label Grid.Row="2" Grid.Column="0">Title</Label> <Label Grid.Row="3" Grid.Column="0">Department</Label> <TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Path=FirstName, Mode=TwoWay}" /> <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Path=LastName, Mode=TwoWay}" /> <TextBox Grid.Row="2" Grid.Column="1" Text="{Binding Path=Title, Mode=TwoWay}" /> <TextBox Grid.Row="3" Grid.Column="1" Text="{Binding Path=Department, Mode=TwoWay}" /> </Grid> </Grid> </Window>
- 代码(注意其中的binding)
- 在xaml文件中设置binding实现业务,在这里需要学习bingding,Trigger,DataTemplate,自定义控件(Style ControlTemplate等WPF Ui相关的知识)
- xaml中已经绑定完了,还需要将ViewModel对象,设定到该xaml文件的DataContext上,就完成了Source的设定。
- 代码:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; using eventDemo.viewModel; namespace eventDemo { /// <summary> /// MainWindow.xaml 的交互逻辑 /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); this.DataContext = new MainWindowViewModel(); } } }
- 代码:
至此就完成了一个基础的MVVM的Demo