wpf-mvvm的冗余ICommand类
本文关键字:ICommand 冗余 wpf-mvvm | 更新日期: 2023-09-27 18:30:03
我仍在学习wpf,但我熟悉如何在wpf c#中设置mvvm。然而,当谈到ICommand/RerelayCommand的东西时,这对我来说有点令人困惑。在过去的几个月里,我编译了一些ICommand类的实现,以便创建我的工具。然而,我现在已经读了几篇文章,并且已经看了足够长的代码,我正在寻找一个人来帮助我,并简单地介绍这里发生了什么,如果是这样,我如何组合/清理这些类。目前,代码似乎是多余的,我不知道如何进行优化。希望这不会要求太多。谢谢
在这篇文章中,我想维护的两件重要的事情是向命令传递参数的能力,如RelayCommand的第一个使用示例所示。第二,启用/禁用第二个命令中的命令的能力。
所以在我的工具中,我有一个helper类。1.我不明白这个RelayCommand.cs中两个类的用法有什么不同。有一个公共类和一个内部类。2.两者都需要吗?还是可以合并?RelayCommand.cs
using System;
using System.Windows.Input;
namespace WpfApplication1.Helper
{
public class RelayCommand<T> : ICommand
{
private readonly Action<T> execute;
private readonly Predicate<T> canExecute;
public RelayCommand(Action<T> execute, Predicate<T> canExecute = null)
{
if (execute == null)
throw new ArgumentNullException("execute");
this.execute = execute;
this.canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
if (parameter == null)
{
return true;
}
else
{
return canExecute == null || canExecute((T)parameter);
}
}
public void Execute(object parameter)
{
execute((T)parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
}
// added
internal class RelayCommand : ICommand
{
private readonly Predicate<object> canExecute;
private readonly Action<object> execute;
public RelayCommand(Action<object> execute, Predicate<object> canExecute = null)
{
if (execute == null)
throw new ArgumentNullException("execute");
this.execute = execute;
this.canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return canExecute == null || canExecute(parameter);
}
public void Execute(object parameter)
{
execute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
}
}
我在名为Customer.cs 的类对象中使用RelayCommand.cs的示例
private ICommand addNewLicense_Command;
public ICommand AddNewLicense_Command
{
get
{
return addNewLicense_Command ?? (addNewLicense_Command = new RelayCommand<Customer>(n =>
{
AddNewLicense_Execute(n);
}));
}
}
因此,在我的MainViewModel.cs中,在我上面提到的Helper类所属的同一项目中,我有另一个ICommand类。这门课有必要吗?它似乎与RelayCommand类非常相似。
public class CommandHandler : ICommand
{
private Action _action;
private bool _canExecute;
public CommandHandler(Action action, bool canExecute)
{
_action = action;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return _canExecute;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
_action();
}
}
我在MainViewModel.cs 中使用CommandHandler的示例
private ICommand addNewUser_Command;
public ICommand AddNewUser_Command
{
get
{
return addNewUser_Command ?? (addNewUser_Command = new CommandHandler(() => AddNewUser_Execute(), true));
}
}
如果您使用像MVVM Lite这样的库,那么它将为您提供RelayCommand实现。无论哪种方式,当你不需要传递参数时,都可以使用非通用的,例如"Ok"按钮:
public ICommand OkCommand { get { return new RelayCommand(Ok); } }
protected virtual void Ok()
{
// ... do something ...
}
关联的XAML类似于:
<Button Content="Ok" Command="{Binding OkCommand}" IsDefault="True" />
当您想要传递参数时,请使用泛型:
public ICommand OpenClientCommand { get { return new RelayCommand<Client>(OnOpenClient); } }
private void OnOpenClient(Client client)
{
// ... do something with client ...
}
在这种情况下,您需要通过命令参数传入客户端对象:
<Button Content="Open" Command="{Binding OpenClientCommand}" CommandParameter="{Binding SelectedClient}"/>
当与事件触发器一起使用时,传递参数也很方便,例如,您可以添加这样的内容来拦截MainWindow的关闭事件:
<i:Interaction.Triggers>
<i:EventTrigger EventName="Closing">
<cmd:EventToCommand Command="{Binding ClosingCommand}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
这个触发器将消息参数传递到处理程序中,在用户没有保存更改的情况下,处理程序可以取消它:
public ICommand ClosingCommand { get { return new RelayCommand<CancelEventArgs>(OnClosing); } }
private void OnClosing(CancelEventArgs args)
{
if (!PromptUserForClose())
args.Cancel = true;
}
您所需要的就是RelayCommand。如果你想禁用该命令,你可以在构造函数中传递一个方法:
return addNewLicense_Command ?? (addNewLicense_Command = new RelayCommand<Customer>(n =>
{
AddNewLicense_Execute(n);
},AllowAddNeLicense));
...
bool AllowAddNewLicense()
{
return _allowAddEnabled;
}
第二个名为CommandHandler的类只是ICommand的另一个实现。不同的是,你可以在构造函数中传递"enabled"布尔值,这意味着除非你创建一个新的实例,否则它将保持不变。在RelayCommand中,你可以传递一个每次都执行的函数,这样你就可以影响结果。