WPF MVVM设计模式实例
本人是WPF初学者,以下实例仅为本人的理解,如有错漏欢迎补充。
我们先看成品样图,并一步一步按此效果完成。
开发环境:Win10、VS2019
(一)实现将学生信息显示与主界面功能。
1.使用WPF模板创建一个项目。
2.新建Model类Student,其中继承的ViewModdelBase需要安装MvvmLightLibs库。
1 public class Student : ViewModelBase 2 { 3 /// <summary> 4 /// id 5 /// </summary> 6 private int id; 7 public int Id 8 { 9 get { return id; } 10 set { id = value; RaisePropertyChanged(); } 11 } 12 13 /// <summary> 14 /// 姓名 15 /// </summary> 16 private string name; 17 public string Name 18 { 19 get { return name; } 20 set { name = value; RaisePropertyChanged(); } 21 } 22 23 /// <summary> 24 /// 性别 25 /// </summary> 26 private string sex; 27 public string Sex 28 { 29 get { return sex; } 30 set { sex = value; RaisePropertyChanged(); } 31 } 32 33 /// <summary> 34 /// 爱好 35 /// </summary> 36 private string hobby; 37 public string Hobby 38 { 39 get { return hobby; } 40 set { hobby = value; RaisePropertyChanged(); } 41 } 42 43 /// <summary> 44 /// 出生日期 45 /// </summary> 46 private DateTime birthDate; 47 public DateTime BirthDate 48 { 49 get { return birthDate; } 50 set { birthDate = value; RaisePropertyChanged(); } 51 } 52 }
3.新建LocalDb类作为本地内存数据库,并支持新增、删除和查询功能。因为MVVM设计模式有通知属性变化的功能,所以自带了修改的效果。
1 public class LocalDb 2 { 3 public LocalDb() 4 { 5 Init(); 6 } 7 8 List<Student> lstStu; 9 public void Init() 10 { 11 lstStu = new List<Student> 12 { 13 new Student 14 { 15 Id = 1, 16 Name = "小明", 17 Sex = "男", 18 Hobby = "篮球、跑步", 19 BirthDate = Convert.ToDateTime("2014/1/14") 20 }, 21 new Student 22 { 23 Id = 2, 24 Name = "小红", 25 Sex = "女", 26 Hobby = "跳绳", 27 BirthDate = Convert.ToDateTime("2014/5/19") 28 }, 29 new Student 30 { 31 Id = 3, 32 Name = "小军", 33 Sex = "男", 34 Hobby = "足球", 35 BirthDate = Convert.ToDateTime("2013/11/14") 36 }, 37 new Student 38 { 39 Id = 4, 40 Name = "小芳", 41 Sex = "女", 42 Hobby = "唱歌、画画", 43 BirthDate = Convert.ToDateTime("2014/3/5") 44 }, 45 new Student 46 { 47 Id = 5, 48 Name = "小李", 49 Sex = "男", 50 Hobby = "武术", 51 BirthDate = Convert.ToDateTime("2014/10/25") 52 } 53 }; 54 } 55 56 public Student GetStudentById(int id) 57 { 58 var data = lstStu.FirstOrDefault(o => o.Id == id); 59 return data; 60 } 61 62 public List<Student> GetStudentByName(string name) 63 { 64 var dataList = lstStu.FindAll(o => o.Name.Contains(name)); 65 return dataList; 66 } 67 68 public void Add(Student stu) 69 { 70 if (stu != null) 71 { 72 lstStu.Add(stu); 73 } 74 } 75 76 public void Del(int id) 77 { 78 var data = lstStu.FirstOrDefault(o => o.Id == id); 79 if (data != null) 80 { 81 lstStu.Remove(data); 82 } 83 } 84 }
4.新建一个ViewStudentModel类,用于创建视图与模型间增删改查操作命令。我们先来把查询功能做出来,然后看一下运行效果。
1 public class ViewStudentModel : ViewModelBase 2 { 3 private string search = string.Empty; 4 public string Search 5 { 6 get { return search; } 7 set { search = value; RaisePropertyChanged(); } 8 } 9 10 private ObservableCollection<Student> gridModelList; 11 public ObservableCollection<Student> GridModelList 12 { 13 get { return gridModelList; } 14 set { gridModelList = value; RaisePropertyChanged(); } 15 } 16 17 public RelayCommand QueryCommand { get; set; } 18 19 private LocalDb localDb; 20 public ViewStudentModel() 21 { 22 localDb = new LocalDb(); 23 QueryCommand = new RelayCommand(Query); 24 } 25 26 public void Query() 27 { 28 var dataList = localDb.GetStudentByName(Search); 29 GridModelList = new ObservableCollection<Student>(); 30 if (dataList != null) 31 { 32 dataList.ForEach(o => GridModelList.Add(o)); 33 } 34 } 35 }
5.在主程序MainWindow.cs类初始化ViewStudentModel类,并调用查询命令,给DataContext赋值,用于UI界面绑定数据。
1 public MainWindow() 2 { 3 InitializeComponent(); 4 5 var view = new ViewStudentModel(); 6 view.Query(); 7 8 this.DataContext = view; 9 }
6.编写UI界面。
1 <Window x:Class="WpfMVVMDemo.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 xmlns:local="clr-namespace:WpfMVVMDemo" 7 mc:Ignorable="d" 8 WindowStartupLocation="CenterScreen" 9 Title="MainWindow" Height="450" Width="800"> 10 <Grid> 11 <Grid.RowDefinitions> 12 <RowDefinition Height="60"></RowDefinition> 13 <RowDefinition></RowDefinition> 14 </Grid.RowDefinitions> 15 16 <StackPanel Orientation="Horizontal"> 17 <TextBlock Text="搜索:" VerticalAlignment="Center" FontSize="16" Margin="10 0 0 0"></TextBlock> 18 <TextBox Text="{Binding Search}" Width="180" Height="25" Margin="10 0 0 0"></TextBox> 19 <Button Command="{Binding QueryCommand}" Content="查询" Width="75" Height="25" Margin="10 0 0 0"></Button> 20 <Button Content="新增" Width="75" Height="25" Margin="10 0 0 0"></Button> 21 <Button Content="重置" Width="75" Height="25" Margin="10 0 0 0"></Button> 22 </StackPanel> 23 24 <DataGrid Grid.Row="1" IsReadOnly="True" ItemsSource="{Binding GridModelList}" AutoGenerateColumns="False" ColumnWidth="*"> 25 <DataGrid.Columns> 26 <DataGridTextColumn Header="Id" Binding="{Binding Id}"> 27 </DataGridTextColumn> 28 <DataGridTextColumn Header="姓名" Binding="{Binding Name}"> 29 </DataGridTextColumn> 30 <DataGridTextColumn Header="性别" Binding="{Binding Sex}"> 31 </DataGridTextColumn> 32 <DataGridTextColumn Header="爱好" Binding="{Binding Hobby}"> 33 </DataGridTextColumn> 34 <DataGridTextColumn Header="出生日期" Binding="{Binding BirthDate, StringFormat='yyyy/MM/dd'}"> 35 </DataGridTextColumn> 36 <DataGridTemplateColumn Header="操作"> 37 <DataGridTemplateColumn.CellTemplate> 38 <DataTemplate> 39 <StackPanel Orientation="Horizontal"> 40 <Button Content="修改" Width="60" Height="25" Foreground="Black" Background="Yellow"></Button> 41 <Button Content="删除" Width="60" Height="25" Foreground="Black" Background="Red"></Button> 42 </StackPanel> 43 </DataTemplate> 44 </DataGridTemplateColumn.CellTemplate> 45 </DataGridTemplateColumn> 46 </DataGrid.Columns> 47 </DataGrid> 48 </Grid> 49 </Window>
此时我们运行就能看到数据了,并且查询功能也可以使用了。
(二)完善新增、修改、删除和重置数据功能。
1.我们先完成简单的删除功能。
首先在ViewStudentModel.cs添加删除命令。
1 public RelayCommand<int> DelCommand { get; set; } 2 3 public ViewStudentModel() 4 { 5 localDb = new LocalDb(); 6 QueryCommand = new RelayCommand(Query); 7 DelCommand = new RelayCommand<int>(Del); 8 } 9 10 public void Del(int id) 11 { 12 var data = localDb.GetStudentById(id); 13 if (data != null) 14 { 15 var r = MessageBox.Show($"是否删除学生:{data.Name}?", "删除学生", MessageBoxButton.YesNoCancel); 16 if (r == MessageBoxResult.Yes) 17 { 18 localDb.Del(id); 19 Query(); 20 } 21 22 } 23 }
然后在UI界面使用删除命令。
1 <Button Content="删除" Width="60" Height="25" Foreground="Black" Background="Red" 2 CommandParameter="{Binding Id}" 3 Command="{Binding DataContext.DelCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid}}"> 4 </Button>
2.接着,我们再完成比较简单的重置功能。
跟删除功能的实现类似,首先在ViewStudentModel.cs添加重置命令。
1 public RelayCommand<int> DelCommand { get; set; } 2 3 public ViewStudentModel() 4 { 5 localDb = new LocalDb(); 6 QueryCommand = new RelayCommand(Query); 7 ResetCommand = new RelayCommand(Reset); 8 DelCommand = new RelayCommand<int>(Del); 9 } 10 11 public void Reset() 12 { 13 Search = string.Empty; 14 localDb.Init(); 15 Query(); 16 }
然后在UI界面使用重置命令。
1 <Button Command="{Binding ResetCommand}" Content="重置" Width="75" Height="25" Margin="10 0 0 0"></Button>
3.添加新增功能。
3.1.新建一个WPF窗体ViewStudent,编写UI界面。
1 <Window x:Class="WpfMVVMDemo.Views.ViewStudent" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 xmlns:local="clr-namespace:WpfMVVMDemo.Views" 7 mc:Ignorable="d" 8 WindowStartupLocation="CenterScreen" 9 Title="ViewStudent" Height="300" Width="300"> 10 <Grid> 11 <Grid.RowDefinitions> 12 <RowDefinition Height="40"></RowDefinition> 13 <RowDefinition></RowDefinition> 14 <RowDefinition Height="40"></RowDefinition> 15 </Grid.RowDefinitions> 16 17 <TextBlock Text="{Binding Title}" FontSize="14" HorizontalAlignment="Left" Margin="10 0 0 0"></TextBlock> 18 19 <Grid Grid.Row="1"> 20 <Grid.ColumnDefinitions> 21 <ColumnDefinition Width="100"></ColumnDefinition> 22 <ColumnDefinition></ColumnDefinition> 23 </Grid.ColumnDefinitions> 24 25 <StackPanel Orientation="Vertical" HorizontalAlignment="Right"> 26 <TextBlock Text="姓名:" Height="25" Margin="0 0 0 0"></TextBlock> 27 <TextBlock Text="性别:" Height="25" Margin="0 20 0 0"></TextBlock> 28 <TextBlock Text="爱好:" Height="25" Margin="0 20 0 0"></TextBlock> 29 <TextBlock Text="出生日期:" Height="25" Margin="0 20 0 0"></TextBlock> 30 </StackPanel> 31 32 <StackPanel Grid.Column="1" Orientation="Vertical" HorizontalAlignment="Left"> 33 <TextBox Text="{Binding Model.Name}" Width="150" Height="25" Margin="0 0 0 0"></TextBox> 34 <ComboBox x:Name="cbSex" Text="{Binding Model.Sex}" Width="150" Height="25" Margin="0 20 0 0"></ComboBox> 35 <TextBox Text="{Binding Model.Hobby}" Width="150" Height="25" Margin="0 20 0 0"></TextBox> 36 <DatePicker Text="{Binding Model.BirthDate}" Width="150" Height="25" Margin="0 20 0 0"></DatePicker> 37 </StackPanel> 38 </Grid> 39 40 <StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Right"> 41 <Button x:Name="btnSave" Click="btnSave_Click" Content="确定" Width="60" Height="25" Margin="0 0 10 0"></Button> 42 <Button x:Name="btnCancel" Click="btnCancel_Click" Content="取消" Width="60" Height="25" Margin="0 0 10 0"></Button> 43 </StackPanel> 44 </Grid> 45 </Window>
3.2.初始化页面资源,使用构造方法接收Model。
1 public partial class ViewStudent : Window 2 { 3 private List<string> lstSex = new List<string> 4 { 5 "男","女","未知" 6 }; 7 8 public ViewStudent(string title, Student stu) 9 { 10 InitializeComponent(); 11 12 this.DataContext = new 13 { 14 Model = stu, 15 Title = title 16 }; 17 18 cbSex.ItemsSource = lstSex; 19 if (title.Equals("新增学生:")) 20 { 21 stu.BirthDate = DateTime.Now; 22 } 23 } 24 25 private void btnCancel_Click(object sender, RoutedEventArgs e) 26 { 27 this.DialogResult = false; 28 } 29 30 private void btnSave_Click(object sender, RoutedEventArgs e) 31 { 32 this.DialogResult = true; 33 } 34 }
3.3.然后跟重置功能的实现类似,首先在ViewStudentModel.cs添加新增命令。
1 public RelayCommand AddCommand { get; set; } 2 3 public ViewStudentModel() 4 { 5 localDb = new LocalDb(); 6 QueryCommand = new RelayCommand(Query); 7 AddCommand = new RelayCommand(Add); 8 ResetCommand = new RelayCommand(Reset); 9 DelCommand = new RelayCommand<int>(Del); 10 } 11 12 public void Add() 13 { 14 var stu = new Student(); 15 var view = new ViewStudent("新增学生:", stu); 16 var r = view.ShowDialog(); 17 if (r.Value) 18 { 19 stu.Id = GridModelList.Max(o => o.Id) + 1; 20 localDb.Add(stu); 21 Query(); 22 } 23 }
3.4.最后在UI界面使用新增命令。
1 <Button Command="{Binding AddCommand}" Content="新增" Width="75" Height="25" Margin="10 0 0 0"></Button>
4.添加编辑功能。因为已经完成添加功能,我们可以继续使用ViewStudent页面,只要将标题改成修改就好了。
4.1.跟删除功能的实现类似,首先在ViewStudentModel.cs添加编辑命令。
1 public RelayCommand<int> EditCommand { get; set; } 2 3 public ViewStudentModel() 4 { 5 localDb = new LocalDb(); 6 QueryCommand = new RelayCommand(Query); 7 AddCommand = new RelayCommand(Add); 8 EditCommand = new RelayCommand<int>(Edit); 9 ResetCommand = new RelayCommand(Reset); 10 DelCommand = new RelayCommand<int>(Del); 11 } 12 13 public void Edit(int id) 14 { 15 var data = localDb.GetStudentById(id); 16 if (data != null) 17 { 18 var tData = new Student 19 { 20 Id = data.Id, 21 Name = data.Name, 22 Sex = data.Sex, 23 Hobby = data.Hobby, 24 BirthDate = data.BirthDate 25 }; 26 27 var view = new ViewStudent("编辑学生:", data); 28 var r = view.ShowDialog(); 29 if (!r.Value) 30 { 31 var model = GridModelList.FirstOrDefault(o => o.Id == id); 32 model.Name = tData.Name; 33 model.Sex = tData.Sex; 34 model.Hobby = tData.Hobby; 35 model.BirthDate = tData.BirthDate; 36 } 37 } 38 }
4.2.然后在UI界面使用修改命令。
1 <Button Content="修改" Width="60" Height="25" Foreground="Black" Background="Yellow" 2 CommandParameter="{Binding Id}" 3 Command="{Binding DataContext.EditCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid}}"></Button>
到现在为止,我们把一个使用MVVM设计模式的WPF项目完成了,并且具有最基本的增删改查功能。