RelayCommand最佳实践

时间:2015-04-06 12:35:24

标签: c# wpf mvvm relaycommand

我和RelayCommands(他们在一个单独的课堂上)工作了大约一个月了,我觉得他们在宣布这些课程时有点笨拙。下面我有3种方法可以想到如何声明RelayCommand

在第一种情况下,我声明了我的ICommand,然后在加载ViewModel时,构建指向我的代码中的方法的RelayCommand

public class MyViewModel
{
    public ICommand MyCommand { get; private set; }

    public MyViewModel()
    {
        MyCommand = new RelayCommand(MyMethod, CanMyMethod);
    }

    private void MyMethod()
    {
         // Do something here ...
    }

    private bool CanMyMethod()
    {
         return string.IsNullOrEmpty(MyString) ? false : true;
    }
}

第二种方法是一次完成所有事情。

public ICommand MyCommand
    {
        get
        {
            return new RelayCommand(
                () =>
                {
                    // Do something here ...
                },
                () =>
                    string.IsNullOrEmpty(MyString) ? false : true);
        }
    }

现在,我计划在某个ViewModel中编写一个具有相当多Commands的应用程序。我也无法在较小的ViewModel中拆分ViewModel,因为所有controls都必须协同工作。

所以我的问题是:

  1. 宣布和构建ICommands的最佳方法是什么?这是我的方法之一还是有更简单的方法?
  2. 考虑到单个ViewModel中有超过50个ICommands,使用每种方法维护概述有多难。
  3. 我希望将来在Windows 7,8和10上发布我的应用程序。如果我只使用.NET4.5,那么我必须考虑RelayCommands是否有任何限制?
  4. 除了RelayCommands我还发现了这个项目:Caliburn-Micro。它允许您执行类似下面的代码。有没有人知道与RelayCommands相比,这在性能方面有多好?这只是一个额外的问题,并且不需要回答将帖子标记为答案。
  5. Xaml(查看)

    <Button x:Name="Login" Content="Log in" />
    

    视图模型

    public bool CanLogin(string username, string password)
    {
        return !String.IsNullOrEmpty(username) && !String.IsNullOrEmpty(password);
    }
    
    public string Login(string username, string password)
    {
        ...
    }
    

3 个答案:

答案 0 :(得分:0)

参考以下答案。

  1. 声明和构建ICommands的最佳方法是什么? 这是我的方法之一还是有更简单的方法? Ans:你可以 采取综合方法。如果你的执行方法非常小,那么你 可以使用RelayCommnd,否则你可以实现自己的ICommand 一个单独的课程。这将提高您的viewmodel的可读性 以及代码的模块化。
  2. 考虑到单个ViewModel中有超过50个ICommands,使用每种方法维护概述有多难。 Ans:在Ans 1中封面
  3. 我希望将来在Windows 7,8和10上发布我的应用程序。如果我只使用.NET4.5,我必须考虑RelayCommands是否有任何限制? Ans:我没有看到Windows 7或8中的任何限制,但对Windows 10不确定。
  4. 除了RelayCommands我还发现了这个项目:Caliburn-Micro。它允许您执行类似下面的代码。有没有人知道与RelayCommands相比,它的性能有多好?这只是一个额外的问题,并且不需要回答将帖子标记为答案。 Ans:我不确定Caliburn-Micro中RelayCommands的源代码。但是如果它使用CommandManager来实现CanExecute功能。然后命令管理器将被触发所有用户输入更改,因此如果在CanExecute方法中有一些重要逻辑,则会导致性能问题。请参阅Are there any performance implications with CanExecuteCommand?

答案 1 :(得分:0)

这是我更喜欢的模式,它基本上是方法1的变体:

public class MyViewModel
{
    private readonly RelayCommand myCommand;

    public MyViewModel()
    {
        this.myCommand = new RelayCommand(this.DoStuff, () => ...);
    }

    public ICommand MyCommand
    {
        get { return this.myCommand; }
    }

    private void DoStuff() { ... }
}

这样做的好处是可以在RelayCommand实现上保留额外的方法(如RaiseCanExecuteChanged),以便在视图模型中使用,但只向消费者公开ICommand个实例。

答案 2 :(得分:-1)

我同意Krowi,第一种方法更容易阅读。但是我会把你的relay命令放到它自己的类中,这样你就可以重用它了:

public class RelayCommand : ICommand
{
    #region Fields
    readonly Action<object> _execute;
    readonly Predicate<object> _canExecute;
    #endregion // Fields

    #region Constructors
    public RelayCommand(Action<object> execute)
        : this(execute, null)
    {
    }

    public RelayCommand(Action<object> execute, Predicate<object> canExecute)
    {
        if (execute == null)
            throw new ArgumentNullException("execute");

        _execute = execute;
        _canExecute = canExecute;
    }
    #endregion

    #region ICommand Members
    [DebuggerStepThrough]
    public bool CanExecute(object parameter)
    {
        return _canExecute == null ? true : _canExecute(parameter);
    }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public void Execute(object parameter)
    {
        _execute(parameter);
    }
    #endregion
}