WPF ICommand MVVM实现
所以在这个特定的MVVM实现中,我需要几个命令。 我真的厌倦了一个一个的实现ICommand类,所以我提出了一个解决scheme,但我不知道它有多好,所以在这里任何WPF专家的input将不胜感激。 如果你能提供更好的解决scheme,甚至更好!
我所做的是一个ICommand类和两个代表,它们将一个对象作为参数,一个代表是void(用于OnExecute),另一个代表是OnCanExecute。 所以在我的ICommand(由ViewModel类调用)的构造函数中,我发送了两个方法,并在每个ICommand方法上调用委托的方法。
它工作得很好,但我不确定这是否是一个不好的方法,或者有更好的方法。 下面是完整的代码,任何input将不胜感激,甚至消极,但请build设性。
谢谢!!
视图模型:
public class TestViewModel : DependencyObject { public ICommand Command1 { get; set; } public ICommand Command2 { get; set; } public ICommand Command3 { get; set; } public TestViewModel() { this.Command1 = new TestCommand(ExecuteCommand1, CanExecuteCommand1); this.Command2 = new TestCommand(ExecuteCommand2, CanExecuteCommand2); this.Command3 = new TestCommand(ExecuteCommand3, CanExecuteCommand3); } public bool CanExecuteCommand1(object parameter) { return true; } public void ExecuteCommand1(object parameter) { MessageBox.Show("Executing command 1"); } public bool CanExecuteCommand2(object parameter) { return true; } public void ExecuteCommand2(object parameter) { MessageBox.Show("Executing command 2"); } public bool CanExecuteCommand3(object parameter) { return true; } public void ExecuteCommand3(object parameter) { MessageBox.Show("Executing command 3"); } }
ICommand的:
public class TestCommand : ICommand { public delegate void ICommandOnExecute(object parameter); public delegate bool ICommandOnCanExecute(object parameter); private ICommandOnExecute _execute; private ICommandOnCanExecute _canExecute; public TestCommand(ICommandOnExecute onExecuteMethod, ICommandOnCanExecute onCanExecuteMethod) { _execute = onExecuteMethod; _canExecute = onCanExecuteMethod; } #region ICommand Members public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } public bool CanExecute(object parameter) { return _canExecute.Invoke(parameter); } public void Execute(object parameter) { _execute.Invoke(parameter); } #endregion }
这与Karl Shifflet如何演示一个RelayCommand
,在那里Execute
触发一个预定的Action<T>
。 一个顶尖的解决scheme,如果你问我。
public class RelayCommand : ICommand { private Predicate<object> _canExecute; private Action<object> _execute; public RelayCommand(Predicate<object> canExecute, Action<object> execute) { this._canExecute = canExecute; this._execute = execute; } public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } public bool CanExecute(object parameter) { return _canExecute(parameter); } public void Execute(object parameter) { _execute(parameter); } }
这可以作为…
public class MyViewModel { private ICommand _doSomething; public ICommand DoSomethingCommand { get { if (_doSomething == null) { _doSomething = new RelayCommand( p => this.CanDoSomething, p => this.DoSomeImportantMethod()); } return _doSomething; } } }
我刚刚创build了一个小例子,展示了如何通过configuration风格实现命令。 但是它需要Reflection.Emit()可用。 支持代码可能看起来有点不可思议,但是一旦写入,可以使用多次。
预告:
public class SampleViewModel: BaseViewModelStub { public string Name { get; set; } [UiCommand] public void HelloWorld() { MessageBox.Show("Hello World!"); } [UiCommand] public void Print() { MessageBox.Show(String.Concat("Hello, ", Name, "!"), "SampleViewModel"); } public bool CanPrint() { return !String.IsNullOrEmpty(Name); } }
}
更新 :现在似乎存在一些像http://www.codeproject.com/Articles/101881/Executing-Command-Logic-in-a-View-Model库解决ICommand样板代码的问题。;
我已经写了关于ICommand接口的这篇文章 。
这个想法 – 创build一个采用两个委托的通用命令:一个在调用ICommand.Execute (object param)
调用,另一个检查是否可以执行该命令的状态(ICommand.CanExecute (object param))
。
需要切换事件CanExecuteChanged
的方法。 它是从用户界面元素中调用的用于切换状态CanExecute()
命令。
public class ModelCommand : ICommand { #region Constructors public ModelCommand(Action<object> execute) : this(execute, null) { } public ModelCommand(Action<object> execute, Predicate<object> canExecute) { _execute = execute; _canExecute = canExecute; } #endregion #region ICommand Members public event EventHandler CanExecuteChanged; public bool CanExecute(object parameter) { return _canExecute != null ? _canExecute(parameter) : true; } public void Execute(object parameter) { if (_execute != null) _execute(parameter); } public void OnCanExecuteChanged() { CanExecuteChanged(this, EventArgs.Empty); } #endregion private readonly Action<object> _execute = null; private readonly Predicate<object> _canExecute = null; }
@Carlo我真的很喜欢你的这个实现,但我想分享我的版本,以及如何在我的ViewModel中使用它
首先实现ICommand
public class Command : ICommand { public delegate void ICommandOnExecute(); public delegate bool ICommandOnCanExecute(); private ICommandOnExecute _execute; private ICommandOnCanExecute _canExecute; public Command(ICommandOnExecute onExecuteMethod, ICommandOnCanExecute onCanExecuteMethod = null) { _execute = onExecuteMethod; _canExecute = onCanExecuteMethod; } #region ICommand Members public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } public bool CanExecute(object parameter) { return _canExecute?.Invoke() ?? true; } public void Execute(object parameter) { _execute?.Invoke(); } #endregion }
注意我从ICommandOnExecute和ICommandOnCanExecute中删除了参数,并向构造函数添加了一个null
然后在ViewModel中使用
public Command CommandToRun_WithCheck { get { return new Command(() => { // Code to run }, () => { // Code to check to see if we can run // Return true or false }); } } public Command CommandToRun_NoCheck { get { return new Command(() => { // Code to run }); } }
我只是觉得这种方式更清洁,因为我不需要分配variables,然后实例化,这一切都一气呵成。