本篇定位
泛型版本 RelayCommand,支持命令参数。
1. 示例一:ListBox 选择
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| public partial class ProductViewModel : ObservableObject { [ObservableProperty] private string _selectedProduct = "";
[RelayCommand] private void SelectProduct(string? productName) { SelectedProduct = productName ?? ""; MessageBox.Show($"选中: {productName}"); }
[RelayCommand(CanExecute = nameof(CanDelete))] private void DeleteProduct(string? productName) { }
private bool CanDelete(string? productName) { return !string.IsNullOrEmpty(productName); } }
|
XAML:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <ListBox ItemsSource="{Binding Products}"> <ListBox.ItemTemplate> <DataTemplate> <StackPanel> <TextBlock Text="{Binding Name}" /> <Button Content="选择" Command="{Binding DataContext.SelectProductCommand, RelativeSource={RelativeSource AncestorType=Window}}" CommandParameter="{Binding Name}" /> <Button Content="删除" Command="{Binding DataContext.DeleteProductCommand, RelativeSource={RelativeSource AncestorType=Window}}" CommandParameter="{Binding Name}" /> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox>
|
2. 示例二:值类型参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| public partial class PaginationViewModel : ObservableObject { [ObservableProperty] private int _currentPage = 1;
[ObservableProperty] private int _totalPages = 10;
[RelayCommand] private void GoToPage(int page) { if (page >= 1 && page <= TotalPages) CurrentPage = page; }
[RelayCommand] private void SetPageSize(int? size) { if (size.HasValue) Console.WriteLine($"每页显示: {size.Value} 条"); } }
|
XAML:
1 2 3 4 5 6 7 8 9 10
| <StackPanel> <Button Content="第3页" Command="{Binding GoToPageCommand}" CommandParameter="3" />
<Button Content="无效" Command="{Binding GoToPageCommand}" CommandParameter="{x:Null}" /> </StackPanel>
|
3. TryGetCommandArgument 源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static bool TryGetCommandArgument(object? parameter, out T? result) { if (parameter is null && default(T) is null) { result = default; return true; }
if (parameter is T argument) { result = argument; return true; }
result = default; return false; }
|
类型处理表:
| T 类型 |
null 参数 |
int 参数 |
string 参数 |
string |
✅ null |
❌ |
✅ |
int |
❌ false |
✅ |
❌ |
int? |
✅ null |
✅ |
❌ |
object |
✅ |
✅ |
✅ |
4. Predicate<T?> 的 CanExecute
1 2 3 4 5 6 7 8
| private readonly Predicate<T?>? canExecute;
[MethodImpl(MethodImplOptions.AggressiveInlining)] public bool CanExecute(T? parameter) { return this.canExecute?.Invoke(parameter) != false; }
|
5. 与非泛型的对比
| 特性 |
RelayCommand |
RelayCommand<T> |
| execute |
Action |
Action<T?> |
| canExecute |
Func<bool> |
Predicate<T?> |
| 参数 |
忽略 |
类型安全转换 |
| null 安全 |
始终通过 |
值类型时返回 false |
| 装箱 |
无 |
值类型参数有 |
下一篇预告:AsyncRelayCommandOptions 源码分析 — 并发执行与异常流控制