编辑
2025-11-25
C#
00

目录

RelayCommand 的主要作用
Nuget 安装包
基本命令实现
同步命令示例
异步命令实现
命令参数传递
注意事项
结论

RelayCommand是CommunityToolkit.Mvvm库中非常强大的命令实现,它简化了MVVM模式中命令的创建和使用。本文将详细探讨RelayCommand的各种应用场景。

RelayCommand 的主要作用

  1. 简化命令创建
    • 提供轻量级的命令实现
    • 减少样板代码
    • 支持无参数和带参数的命令
  2. 解耦用户交互逻辑
    • 将界面交互逻辑从视图中分离
    • 提高代码的可测试性和可维护性

Nuget 安装包

image.png

基本命令实现

同步命令示例

C#
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; namespace App06 { // ViewModel public partial class UserViewModel : ObservableObject { // 无参数同步命令 [RelayCommand] private void SaveUser() { // 执行保存用户逻辑 MessageBox.Show("用户信息已保存"); } // 带条件的同步命令 [RelayCommand(CanExecute = nameof(CanSaveUser))] private void SaveUserWithCondition() { MessageBox.Show("带条件的用户保存"); } // 命令是否可执行的条件方法 private bool CanSaveUser() => !string.IsNullOrEmpty(UserName); // 属性 private string _userName; public string UserName { get => _userName; set { // 使用SetProperty更新属性并通知UI SetProperty(ref _userName, value); // 触发命令的可执行状态更新 SaveUserWithConditionCommand.NotifyCanExecuteChanged(); } } } }
C#
namespace App06 { public partial class Form1 : Form { private UserViewModel _viewModel; public Form1() { InitializeComponent(); // 初始化ViewModel _viewModel = new UserViewModel(); // 绑定数据和命令 BindViewModel(); } private void BindViewModel() { // 文本框绑定UserName属性 txtUserName.DataBindings.Add( new Binding("Text", _viewModel, "UserName", true, DataSourceUpdateMode.OnPropertyChanged) ); // 绑定无条件保存按钮 btnSaveUser.Click += (s, e) => _viewModel.SaveUserCommand.Execute(null); // 绑定带条件保存按钮 btnSaveUserWithCondition.Click += (s, e) => _viewModel.SaveUserWithConditionCommand.Execute(null); // 初始时禁用带条件的保存按钮 btnSaveUserWithCondition.Enabled = false; // 监听命令的可执行状态变化 _viewModel.SaveUserWithConditionCommand.CanExecuteChanged += (s, e) => { btnSaveUserWithCondition.Enabled = _viewModel.SaveUserWithConditionCommand.CanExecute(null); }; } } }

image.png

异步命令实现

C#
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; namespace App06 { public partial class NetworkViewModel : ObservableObject { private readonly HttpClient _httpClient; private CancellationTokenSource _cts; // 数据属性 private string _fetchedData; public string FetchedData { get => _fetchedData; set => SetProperty(ref _fetchedData, value); } // 加载状态属性 private bool _isLoading; public bool IsLoading { get => _isLoading; set => SetProperty(ref _isLoading, value); } // 错误信息属性 private string _errorMessage; public string ErrorMessage { get => _errorMessage; set => SetProperty(ref _errorMessage, value); } public NetworkViewModel() { // 初始化HttpClient _httpClient = new HttpClient(); } // 异步命令示例 [RelayCommand] public async Task FetchDataAsync() { // 取消之前的请求 _cts?.Cancel(); _cts = new CancellationTokenSource(); try { IsLoading = true; var token = _cts.Token; var response = await _httpClient.GetAsync("https://jsonplaceholder.typicode.com/posts/1"); response.EnsureSuccessStatusCode(); FetchedData = await response.Content.ReadAsStringAsync(); } catch (OperationCanceledException) { ErrorMessage = "请求已取消"; } catch (HttpRequestException ex) { ErrorMessage = $"网络请求失败: {ex.Message}"; } finally { IsLoading = false; } } } }
C#
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using static System.Windows.Forms.VisualStyles.VisualStyleElement; namespace App06 { public partial class Form2 : Form { private bool InverseBoolean(bool value) => !value; private NetworkViewModel _viewModel; public Form2() { InitializeComponent(); // 初始化ViewModel _viewModel = new NetworkViewModel(); // 绑定ViewModel BindViewModel(); } private void BindViewModel() { // 绑定数据显示 txtFetchedData.DataBindings.Add( new Binding("Text", _viewModel, "FetchedData", true, DataSourceUpdateMode.OnPropertyChanged) ); // 绑定错误消息 lblErrorMessage.DataBindings.Add( new Binding("Text", _viewModel, "ErrorMessage", true, DataSourceUpdateMode.OnPropertyChanged) ); // 进度条绑定 pbar.DataBindings.Add( new Binding("Visible", _viewModel, "IsLoading", true, DataSourceUpdateMode.OnPropertyChanged) ); } private async void btnFetchData_Click(object sender, EventArgs e) { try { btnFetchData.Enabled = false; await _viewModel.FetchDataAsync(); } catch (Exception ex) { MessageBox.Show($"执行失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); } finally { // 始终确保按钮可用 btnFetchData.Enabled = true; } } } }

image.png

命令参数传递

C#
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace App06 { // 用户模型 public class User { public string Name { get; set; } public int Age { get; set; } } }
C#
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; namespace App06 { // ViewModel public partial class ParameterCommandViewModel : ObservableObject { // 属性绑定 [ObservableProperty] private string nameInput; [ObservableProperty] private int ageInput; // 接收字符串参数的命令 [RelayCommand] private void ProcessName(string name) { MessageBox.Show($"处理名称: {name}"); } // 接收复杂对象参数的命令 [RelayCommand] private void UpdateUser(User user) { MessageBox.Show($"更新用户: {user.Name}, 年龄: {user.Age}"); } // 创建用户的命令 [RelayCommand] private void CreateUser() { var newUser = new User { Name = NameInput, Age = AgeInput }; UpdateUser(newUser); } } }
C#
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.Xml.Linq; namespace App06 { public partial class Form3 : Form { private ParameterCommandViewModel viewModel; public Form3() { InitializeComponent(); InitializeViewModel(); SetupBindings(); } private void InitializeViewModel() { viewModel = new ParameterCommandViewModel(); } private void SetupBindings() { // 绑定文本框到ViewModel的属性 txtName.DataBindings.Add( "Text", viewModel, nameof(ParameterCommandViewModel.NameInput), true, DataSourceUpdateMode.OnPropertyChanged ); txtAge.DataBindings.Add( "Text", viewModel, nameof(ParameterCommandViewModel.AgeInput), true, DataSourceUpdateMode.OnPropertyChanged ); // 绑定按钮到命令 btnProcessName.Click += (s, e) => viewModel.ProcessNameCommand.Execute(txtName.Text); btnCreateUser.Click += (s, e) => viewModel.CreateUserCommand.Execute(null); } } }

image.png

注意事项

  • RelayCommand默认在UI线程执行
  • 异步命令建议添加错误处理
  • 使用部分类和源生成器获得最佳性能

结论

CommunityToolkit.MvvmRelayCommand提供了强大且灵活的命令实现方式,极大地简化了MVVM开发中的命令逻辑。

本文作者:技术老小子

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!