ICommand MVVM实现

Car*_*rlo 58 .net c# wpf mvvm icommand

所以在我正在做的这个特定的MVVM实现中,我需要几个命令.我真的厌倦了逐个实现ICommand类,所以我提出了一个解决方案,但我不知道它有多好,所以任何WPF专家的输入都将非常感激.如果你能提供更好的解决方案,那就更好了.

我所做的是一个ICommand类和两个代理,它们将一个对象作为参数,一个委托是void(对于OnExecute),另一个是bool(对于OnCanExecute).因此,在我的ICommand的构造函数(由ViewModel类调用)中,我发送了两个方法,并在每个ICommand方法上调用委托的方法.

它的效果非常好,但我不确定这是不是一个糟糕的方法,或者是否有更好的方法.下面是完整的代码,任何输入都会非常感激,甚至是负面的,但请建设性的.

视图模型:

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");
    }
}
Run Code Online (Sandbox Code Playgroud)

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
}
Run Code Online (Sandbox Code Playgroud)

Jar*_*yer 69

这几乎与Karl Shifflet演示的一样RelayCommand,在那里Execute发射预定的Action<T>.如果你问我,这是一个顶尖的解决方案.

public class RelayCommand : ICommand
{
    private readonly Predicate<object> _canExecute;
    private readonly Action<object> _execute;

    public RelayCommand(Predicate<object> canExecute, Action<object> execute)
    {
        _canExecute = canExecute;
        _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);
    }
}
Run Code Online (Sandbox Code Playgroud)

这可以用作......

public class MyViewModel
{
    private ICommand _doSomething;
    public ICommand DoSomethingCommand
    {
        get
        {
            if (_doSomething == null)
            {
                _doSomething = new RelayCommand(
                    p => this.CanDoSomething,
                    p => this.DoSomeImportantMethod());
            }
            return _doSomething;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

阅读更多:
Josh Smith(介绍人RelayCommand):模式 - 使用MVVM设计模式的WPF应用程序

  • 我使用这种方法,因为我正在使用MVVM,它就像一个魅力;) (2认同)

小智 14

我写过这篇关于ICommand接口的文章.

这个想法-建立一个普遍的命令有两个代表:一个被称为时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;
}
Run Code Online (Sandbox Code Playgroud)


Bor*_*hov 10

我刚刚创建了一个小例子,展示了如何在约定中实现命令而非配置样式.但是它需要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);
    }
}
Run Code Online (Sandbox Code Playgroud)

}

更新:现在似乎存在一些像http://www.codeproject.com/Articles/101881/Executing-Command-Logic-in-a-View-Model这样的库来解决ICommand样板代码的问题.


小智 6

@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
}
Run Code Online (Sandbox Code Playgroud)

注意我已经从ICommandOnExecuteICommandOnCanExecute 中删除了参数,并在构造函数中添加了一个空值

然后在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
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

我只是觉得这种方式更干净,因为我不需要分配变量然后实例化,这一切都一次性完成。