WPF MVVM利器CommunityToolkit.Mvvm.入门
开发WPF桌面程序时需要用到MVVM框架,而以往用的MVVMLight 早已停更,目前大多使用微软官方的CommunityToolkit.Mvvm作为替代方案,本期做一个简易的CommunityToolkit.Mvvm入门案例,以供参考
开发环境VS2022+.NET8.0
1.新建WPF项目,nuget引用CommunityToolkit.Mvvm和Microsoft.Extensions.DependencyInjection
2.项目中新建Models文件夹
添加类 Student.cs
using Microsoft.Extensions.DependencyInjection; using System.Configuration; using System.Data; using System.Windows; using WpfApp3.Service; using WpfApp3.ViewModels; namespace WpfApp3 { /// <summary> /// Interaction logic for App.xaml /// </summary> public partial class App : Application { public IServiceProvider ServiceProvider { get; private set; } public new static App Current => (App)Application.Current; public App() { ServiceProvider = ConfigurationServices(); } private static IServiceProvider ConfigurationServices() { var services = new ServiceCollection(); services.AddTransient<MainWindowViewModel>(); services.AddTransient<EditViewModel>(); services.AddSingleton<StudentService>(); return services.BuildServiceProvider(); } } }
3.新建ViewModels文件夹,新建类EditViewModel.cs, MainWindowViewModel.cs
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Messaging; using Microsoft.Extensions.DependencyInjection; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Input; using WpfApp3.Message; using WpfApp3.Models; using WpfApp3.Service; namespace WpfApp3.ViewModels { public partial class EditViewModel : ObservableObject { private StudentService _studentService; private Student _studentInfo; //简易写法自动生成StudentInfo属性 [ObservableProperty] private Student studentInfo; public ICommand SaveCommand { get; private set; } //自动生成CancelCommand [RelayCommand] public void Cancel()=> Application.Current.Windows.OfType<EditWindow>().FirstOrDefault()?.Close(); // 新增构造 public EditViewModel() { _studentService = new StudentService(); StudentInfo = new Student(); InitCommand(); } // 修改构造 public EditViewModel(Student model) { _studentService = App.Current.ServiceProvider.GetRequiredService<StudentService>(); StudentInfo = model; InitCommand(); } private void InitCommand() { // 保存 SaveCommand = new RelayCommand(() => { if (string.IsNullOrWhiteSpace(StudentInfo.Name)) { MessageBox.Show("姓名不能为空"); return; } bool flag; if (StudentInfo.Id == 0) { flag = _studentService.Add(StudentInfo); } else { flag = _studentService.Update(StudentInfo); } if (flag) { // 发送刷新消息 WeakReferenceMessenger.Default.Send(new RefreshMsg { IsRefresh = true }); // 关闭当前窗口 Application.Current.Windows.OfType<EditWindow>().FirstOrDefault()?.Close(); } }); //// 取消 //CancelCommand = new RelayCommand(() => //{ // Application.Current.Windows.OfType<EditWindow>().FirstOrDefault()?.Close(); //}); } } }
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Messaging; using Microsoft.Extensions.DependencyInjection; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Input; using WpfApp3.Message; using WpfApp3.Models; using WpfApp3.Service; namespace WpfApp3.ViewModels { public partial class MainWindowViewModel:ObservableObject { private Student student; private readonly StudentService _studentService; // 学生集合 private ObservableCollection<Student> _students; public ObservableCollection<Student> Students { get => _students; set => SetProperty(ref _students, value); } public Student Student { get { return student; } set { student = value; } } // 选中学生 private Student _selectedStudent; public Student SelectedStudent { get => _selectedStudent; set => SetProperty(ref _selectedStudent, value); } //简易写法 [ObservableProperty] private string keyword; //简易写法 [RelayCommand] private void Search() { Students = new ObservableCollection<Student>(_studentService.Search(Keyword)); } public MainWindowViewModel() { _studentService = App.Current.ServiceProvider.GetRequiredService<StudentService>(); student = new Student(); LoadData(); InitCommand(); // 注册刷新消息 WeakReferenceMessenger.Default.Register<RefreshMsg>(this, (recipient, msg) => { if (msg.IsRefresh) { LoadData(); } }); } // 加载数据 private void LoadData() { Students = new ObservableCollection<Student>(_studentService.GetAll()); } // 命令 public ICommand AddCommand { get; private set; } public ICommand EditCommand { get; private set; } public ICommand DeleteCommand { get; private set; } // 初始化命令 private void InitCommand() { // 新增 AddCommand = new RelayCommand(() => { new EditWindow().ShowDialog(); }); // 编辑 EditCommand = new RelayCommand(() => { if (SelectedStudent == null) { MessageBox.Show("请选择一条数据"); return; } new EditWindow(SelectedStudent).ShowDialog(); }); // 删除 DeleteCommand = new RelayCommand(() => { if (SelectedStudent == null) { MessageBox.Show("请选择一条数据"); return; } var result = MessageBox.Show("确认删除?", "提示", MessageBoxButton.YesNo); if (result == MessageBoxResult.Yes) { _studentService.Delete(SelectedStudent.Id); LoadData(); } }); } private bool CanExecute() { if (student.Age > 18) { MessageBox.Show("年龄太大了..."); return false; } else { return true; } } private ICommand saveCommand; public ICommand SaveCommand => saveCommand ??= new RelayCommand(Save,CanExecute); private void Save() { _studentService.Add(student); WeakReferenceMessenger.Default.Send(new RefreshMsg { IsRefresh = true }); MessageBox.Show($"需要保存的信息为Id={Student.Id},Name={Student.Name}!"); } } }
4.新建Service文件夹,和StudentService.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using WpfApp3.Models; namespace WpfApp3.Service { public class StudentService { // 模拟数据 private List<Student> _studentList = new List<Student> { new Student{Id=1,Name="张三",Age=17,ClassName="高一(1)"}, new Student{Id=2,Name="李四",Age=18,ClassName="高一(2)"}, new Student{Id=3,Name="王五",Age=17,ClassName="高一(1)"}, new Student{Id=4,Name="宋五",Age=17,ClassName="高一(1)"} }; // 查询全部 public List<Student> GetAll() => _studentList; // 新增 public bool Add(Student model) { model.Id = _studentList.Max(x => x.Id) + 1; _studentList.Add(model); return true; } // 修改 public bool Update(Student model) { var item = _studentList.FirstOrDefault(x => x.Id == model.Id); if (item == null) return false; item.Name = model.Name; item.Age = model.Age; item.ClassName = model.ClassName; return true; } // 删除 public bool Delete(int id) { var item = _studentList.FirstOrDefault(x => x.Id == id); if (item == null) return false; _studentList.Remove(item); return true; } // 搜索 public List<Student> Search(string keyword) { if (string.IsNullOrWhiteSpace(keyword)) return GetAll(); return _studentList.Where(x => x.Name.Contains(keyword)).ToList(); } } }
5.新建Message文件夹和RefreshMsg.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace WpfApp3.Message { public class RefreshMsg { // 标记是否需要刷新列表 public bool IsRefresh { get; set; } } }
6.设置App.xaml
using Microsoft.Extensions.DependencyInjection; using System.Configuration; using System.Data; using System.Windows; using WpfApp3.Service; using WpfApp3.ViewModels; namespace WpfApp3 { /// <summary> /// Interaction logic for App.xaml /// </summary> public partial class App : Application { public IServiceProvider ServiceProvider { get; private set; } public new static App Current => (App)Application.Current; public App() { ServiceProvider = ConfigurationServices(); } private static IServiceProvider ConfigurationServices() { var services = new ServiceCollection(); services.AddTransient<MainWindowViewModel>(); services.AddTransient<EditViewModel>(); services.AddSingleton<StudentService>(); return services.BuildServiceProvider(); } } }
7.新建窗体EditWindow
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 WpfApp3.Models; using WpfApp3.ViewModels; namespace WpfApp3 { /// <summary> /// EditWindow.xaml 的交互逻辑 /// </summary> public partial class EditWindow : Window { public EditWindow() { InitializeComponent(); } // 修改 public EditWindow(Student model) { InitializeComponent(); // 传递数据 (DataContext as EditViewModel).StudentInfo = model; } } }
<Window x:Class="WpfApp3.EditWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfApp3" xmlns:vm="clr-namespace:WpfApp3.ViewModels" mc:Ignorable="d" Title="学生信息" Height="400" Width="400" ResizeMode="NoResize"> <Window.DataContext> <vm:EditViewModel/> </Window.DataContext> <Grid Margin="20"> <StackPanel> <StackPanel Margin="0 10"> <TextBlock Text="姓名"/> <TextBox Text="{Binding StudentInfo.Name,Mode=TwoWay}" Height="25"/> </StackPanel> <StackPanel Margin="0 10"> <TextBlock Text="年龄"/> <TextBox Text="{Binding StudentInfo.Age,Mode=TwoWay}" Height="25"/> </StackPanel> <StackPanel Margin="0 10"> <TextBlock Text="班级"/> <TextBox Text="{Binding StudentInfo.ClassName,Mode=TwoWay}" Height="25"/> </StackPanel> <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0 15 0 0"> <Button Content="保存" Command="{Binding SaveCommand}" Width="70" Height="28" Margin="5"/> <Button Content="取消" Command="{Binding CancelCommand}" Width="70" Height="28" Margin="5"/> </StackPanel> </StackPanel> </Grid> </Window>
8.新建窗体 MainWindow
using System.Text; 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.Navigation; using System.Windows.Shapes; using WpfApp3.ViewModels; namespace WpfApp3 { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); this.DataContext = App.Current.ServiceProvider.GetService(typeof(MainWindowViewModel)); } } }
<Window x:Class="WpfApp3.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfApp3" mc:Ignorable="d" Title="学生管理系统" Height="450" Width="700"> <Grid Margin="15"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <!--搜索栏--> <StackPanel Grid.Row="0" Orientation="Horizontal" Margin="0 0 0 10"> <TextBox Text="{Binding Keyword,Mode=TwoWay}" Width="200" Height="25" /> <Button Content="搜索" Command="{Binding SearchCommand}" Width="80" Height="28" Margin="5"/> </StackPanel> <!--数据列表--> <DataGrid Grid.Row="1" ItemsSource="{Binding Students}" SelectedItem="{Binding SelectedStudent}" AutoGenerateColumns="False" CanUserAddRows="False"> <DataGrid.Columns> <DataGridTextColumn Header="学号" Binding="{Binding Id}" Width="80"/> <DataGridTextColumn Header="姓名" Binding="{Binding Name}" Width="120"/> <DataGridTextColumn Header="年龄" Binding="{Binding Age}" Width="80"/> <DataGridTextColumn Header="班级" Binding="{Binding ClassName}" Width="150"/> </DataGrid.Columns> </DataGrid> <!--操作按钮--> <StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0 10 0 0"> <Button Content="新增" Command="{Binding AddCommand}" Width="80" Height="28" Margin="5"/> <Button Content="编辑" Command="{Binding EditCommand}" Width="80" Height="28" Margin="5"/> <Button Content="删除" Command="{Binding DeleteCommand}" Width="80" Height="28" Margin="5"/> </StackPanel> </Grid> </Window>

浙公网安备 33010602011771号