接下来我们通过两节课程使用MVVM来开发一个简单的Demo,首先我们创建一个项目名称WPF-22-MVVM-Demo,目录结构如下:
我们在Models文件下创建Employee类并让该类实现INotifyPropertyChanged接口,该类中定义编号、姓名和角色三个基本属性
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace WPF_22_MVVM_Demo.Models
{
public class Employee : INotifyPropertyChanged
{
private string no = String.Empty;
public string No
{
get
{
return no;
}
set
{
if (value != this.no)
{
no = value;
NotifyPropertyChanged();
}
}
}
private string name = String.Empty;
public string Name
{
get
{
return name;
}
set
{
if (value != this.name)
{
this.name = value;
NotifyPropertyChanged();
}
}
}
private string role = String.Empty;
public string Role
{
get
{
return role;
}
set
{
if (value != this.role)
{
this.role = value;
NotifyPropertyChanged();
}
}
}
public event PropertyChangedEventHandler? PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
在Models文件下定义服务EmployeeService,该类可以包含一些常用业务操作,例如:对远程api调用操作远程数据库以及本地数据库操作等,在该例子中,我们对一个内存对象集合实现增删改查操作
using System.Collections.Generic;
using System.Linq;
namespace WPF_22_MVVM_Demo.Models
{
public class EmployeeService
{
private static List<Employee> _employees = null!;
public EmployeeService()
{
_employees = new List<Employee>()
{
new Employee()
{
No="800001",
Name="张三丰",
Role="武当派掌门人"
},
new Employee()
{
No="800002",
Name="乔峰",
Role="乞丐掌门人"
},
};
}
public List<Employee> GetEmployees()
{
return _employees;
}
}
}
在Commands文件夹下定义DelegateCommand
using System;
using System.Windows.Input;
namespace WPF_22_MVVM_Demo.Commands
{
public class DelegateCommand : ICommand
{
private Action _execute;
private Func<bool> _canExecute;
public DelegateCommand(Action executeMethod)
{
_execute = executeMethod;
}
public DelegateCommand(Action executeMethod, Func<bool> canExecute)
: this(executeMethod)
{
this._canExecute = canExecute;
}
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
_execute();
}
}
}
在ViewModes文件加下创建EmployeeViewMode,同时该类实现INotifyPropertyChanged接口,该类引用了Employee 实体(用来绑定到UI页面)和EmployeeService服务以及DelegateCommand 类
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Input;
using WPF_22_MVVM_Demo.Commands;
using WPF_22_MVVM_Demo.Models;
namespace WPF_22_MVVM_Demo.ViewModes
{
public class EmployeeViewMode : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
EmployeeService employeeService;
public EmployeeViewMode()
{
employeeService = new EmployeeService();
BindData();
Employee = new Employee();
}
private Employee employee;
public Employee Employee
{
get { return employee; }
set { employee = value;NotifyPropertyChanged(); }
}
private ObservableCollection<Employee> employeeList;
public ObservableCollection<Employee> EmployeeList
{
get
{
return employeeList;
}
set
{
employeeList = value;
NotifyPropertyChanged();
}
}
/// <summary>
///消息提示
/// </summary>
public string Message
{
get;
set;
}
/// <summary>
/// DataGrid绑定数据
/// </summary>
public void BindData()
{
EmployeeList = new ObservableCollection<Employee>(employeeService.GetEmployees());
}
}
}
在Views文件加下创建EmployeeView.xaml,将窗体的DataContext指向EmployeeViewMode,在该界面有两部分组成:
录入信息,将文本框和EmployeeViewMode中的Employee对象的属性做绑定
DataGrid展示数据列表,将控件的ItemsSource属性绑定EmployeeViewMode对象中的EmployeeList属性
<UserControl x:Class="WPF_22_MVVM_Demo.Views.EmployeeView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="0.1*"></RowDefinition>
<RowDefinition Height="0.1*"></RowDefinition>
<RowDefinition Height="0.1*"></RowDefinition>
<RowDefinition Height="0.1*"></RowDefinition>
<RowDefinition Height="0.6*"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.35*"></ColumnDefinition>
<ColumnDefinition Width="0.65*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Margin="10">员工编号</TextBlock>
<TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Path=Employee.No}" Width="150" HorizontalAlignment="Left" Margin="10"/>
<TextBlock Grid.Row="1" Grid.Column="0" Margin="10">员工姓名</TextBlock>
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Path=Employee.Name}" Width="150" HorizontalAlignment="Left" Margin="10"></TextBox>
<TextBlock Grid.Row="2" Grid.Column="0" Margin="10">角色</TextBlock>
<TextBox Grid.Row="2" Grid.Column="1" Text="{Binding Path=Employee.Role}" Width="150" HorizontalAlignment="Left" Margin="10"></TextBox>
<StackPanel Grid.Row="3" Grid.ColumnSpan="2" Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Top">
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
</Grid>
<Button Content="新增" Width="100" Height="30" Margin="2"></Button>
<Button Content="修改" Width="100" Height="30" Margin="2"></Button>
<Button Content="删除" Width="100" Height="30" Margin="2"></Button>
<Button Content="查询" Width="100" Height="30" Margin="2"></Button>
</StackPanel>
<DataGrid Grid.Row="4" Grid.ColumnSpan="2" Name="empGrid" AutoGenerateColumns="False" ItemsSource="{Binding Path=EmployeeList,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
<DataGrid.Columns>
<DataGridTextColumn Header="员工编号" Width="0.3*" Binding="{Binding Path=No,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"></DataGridTextColumn>
<DataGridTextColumn Header="姓名" Width="0.3*" Binding="{Binding Path=Name,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"></DataGridTextColumn>
<DataGridTextColumn Header="角色" Width="0.3*" Binding="{Binding Path=Role,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"></DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</UserControl>
using System.Windows.Controls;
using WPF_22_MVVM_Demo.ViewModes;
namespace WPF_22_MVVM_Demo.Views
{
/// <summary>
/// Interaction logic for EmployeeView.xaml
/// </summary>
public partial class EmployeeView : UserControl
{
public EmployeeView()
{
InitializeComponent();
this.DataContext = new EmployeeViewMode();
}
}
}
在MainWindow.xaml窗体中引用EmployeeView
<Window x:Class="WPF_22_MVVM_Demo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:EmpView="clr-namespace:WPF_22_MVVM_Demo.Views"
mc:Ignorable="d"
Title="员工管理" Height="450" Width="500">
<StackPanel>
<EmpView:EmployeeView></EmpView:EmployeeView>
</StackPanel>
</Window>
运行如下:
这节我们主要介绍MVVM项目整体结构以及UI页面布局,并且将控件和ViewModel数据模型进行了绑定,实现了最基本DataGrid数据绑定,在接下来我们将实现增删改查
WPF中Command绑定引用了设计模式中的命令模式(Command Pattern)