15

将命令抽象到视图模型中是 XAML/MVVM 项目的宝贵实践。我明白了。而且,我在 WinRT 中看到了 ICommand;但是,我们如何实施呢?我还没有找到真正有效的样本。有人知道吗?

4

5 回答 5

20

我一直最喜欢的是 Microsoft 模式和实践团队提供的 DelegateCommand。它允许您创建一个键入的命令:

MyCommand = new DelegateCommand<MyEntity>(OnExecute);
...
private void OnExecute(MyEntity entity)
{...}

它还提供了一种引发 CanExecuteChanged 事件的方法(禁用/启用命令)

MyCommand.RaiseCanExecuteChanged();

这是代码:

public class DelegateCommand<T> : ICommand
{
    private readonly Func<T, bool> _canExecuteMethod;
    private readonly Action<T> _executeMethod;

    #region Constructors

    public DelegateCommand(Action<T> executeMethod)
        : this(executeMethod, null)
    {
    }

    public DelegateCommand(Action<T> executeMethod, Func<T, bool> canExecuteMethod)
    {
        _executeMethod = executeMethod;
        _canExecuteMethod = canExecuteMethod;
    }

    #endregion Constructors

    #region ICommand Members

    public event EventHandler CanExecuteChanged;

    bool ICommand.CanExecute(object parameter)
    {
        try
        {
            return CanExecute((T)parameter);
        }
        catch { return false; }
    }

    void ICommand.Execute(object parameter)
    {
        Execute((T)parameter);
    }

    #endregion ICommand Members

    #region Public Methods

    public bool CanExecute(T parameter)
    {
        return ((_canExecuteMethod == null) || _canExecuteMethod(parameter));
    }

    public void Execute(T parameter)
    {
        if (_executeMethod != null)
        {
            _executeMethod(parameter);
        }
    }

    public void RaiseCanExecuteChanged()
    {
        OnCanExecuteChanged(EventArgs.Empty);
    }

    #endregion Public Methods

    #region Protected Methods

    protected virtual void OnCanExecuteChanged(EventArgs e)
    {
        var handler = CanExecuteChanged;
        if (handler != null)
        {
            handler(this, e);
        }
    }

    #endregion Protected Methods
}
于 2012-08-15T05:23:14.920 回答
3

查看RelayCommand类(仅 METRO 代码)。该NotifyPropertyChanged课程可以在这里找到。该类NotifyPropertyChanged仅用于允许绑定CanExecute并使用RaiseCanExecuteChanged.

原始的中继命令类可以在这里找到

于 2012-08-14T23:14:24.793 回答
2

不幸的是,似乎没有为您实现它的本机类。如果您想自己实现该接口并不太复杂,并且流行的MVVM Lite工具包包含其自己的RelayCommand版本。您可以通过右键单击 References 并选择“Manage NuGet Packages”将 MVVM Lite 添加到您的项目中。如果您没有此选项,请在Tools -> Extensions and Updates下启用 Nuget 。

于 2012-08-15T02:24:05.097 回答
0

我一直在寻找 XAML-MVVM 命令的最小端到端实现,但还没有找到。

因此,按照#Rico 的回答,我最终得到了以下作为最小 RelayCommand 的工作。我在一个大型项目中使用了类似的最小版本。

public class RelayCommand : System.Windows.Input.ICommand {

    readonly Action<object> execute; 

    public RelayCommand(Action<object> execute) {
        this.execute = execute;
    }

    public bool CanExecute(object parameter) {
        return true;
    }

    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter) {
        this.execute(parameter);
    }
}

CanExecute较大的 RelayCommand 类似乎提供了对and的更多控制CanExecuteChanged,但您不需要它来开始 - 而且您可能根本不需要它。

要在视图模型中使用它:

class ViewModel : INotifyPropertyChanged {

    << ... snip VM properties and notifications ...>>

    public RelayCommand DoSomethingCommand {
        get {
            return new RelayCommand(param => {
                this.DoSomething(param as AType);
                Debug.WriteLine("Command Executed");
            });
        }

    }
}

(我们不需要命令的 INotifyPropertyChanged,但任何视图模型通常都会实现它。)

最后,XAML...

   <Grid>
        <!-- Set the data context here, for illustration. -->
        <Grid.DataContext>
            <local:ViewModel/>
        </Grid.DataContext>
        <!-- A sample control bind to a property -->
        <TextBlock 
             Text="{Binding AProp}"/>
        <!-- Bind a command -->
        <Button Command="{Binding DoSomethingCommand}" CommandParameter="foo">Change!</Button>
    </Grid>
于 2014-09-24T04:36:12.883 回答
0

我在https://code.msdn.microsoft.com/windowsapps/Working-with-ICommand-690ba1d4找到了这个非常好的示例

<Page.Resources> 
        <local:MyCommandsCollection x:Key="MyCommands" /> 
</Page.Resources> 

   <Button Width="280" 
            Height="59" 
            Margin="513,280,0,0" 
            HorizontalAlignment="Left" 
            VerticalAlignment="Top" 
            Command="{Binding MyFirstCommand}" 
            CommandParameter="{Binding Text, 
                                       ElementName=myTextBox}" 
            Content="Execute Command" /> 


public class MyCommandsCollection 
{ 
    public MyCommand MyFirstCommand 
    { 
        get { return new MyCommand(); } 
    } 
} 

public class MyCommand : ICommand 
    { 
        public bool CanExecute(object parameter) 
        { 
            return true; 
        } 

        public event EventHandler CanExecuteChanged; 

        public async void Execute(object parameter) 
        { 
            MessageDialog message = new MessageDialog( 
                "The command is executing, the value of the TextBox is " + parameter as String); 
            await message.ShowAsync(); 
        } 
    }

我用 x:Bind 试过了,效果很好。我所需要的只是在我的 ViewModel 中公开一个属性,该属性返回“MyCommand”类的一个新实例,这一切都很好。

由于我在我的 XAML 中设置 DataContext,我不需要弄乱任何“MyCommandCollection”的东西。耶编译绑定。

于 2015-09-29T20:57:20.197 回答