检测从ViewModel WPF

时间:2016-11-14 23:49:39

标签: c# wpf button mvvm

我的WPF-App主窗口上有很多按钮。 这些按钮的命令应该具有相同的实现/功能,但是根据按下的按钮,函数访问的文件/路径会发生变化。 如何在不使用按钮单击事件处理程序(Windows窗体)的情况下检测从ViewModel单击的按钮?

以下是类RelayCommand的实现:

public class RelayCommand : ICommand
{

    readonly Func<Boolean> _canExecute;
    readonly Action _execute;


    public RelayCommand(Action execute)
        : this(execute, null)
    {
    }

    public RelayCommand(Action execute, Func<Boolean> canExecute)
    {
        if (execute == null)
            throw new ArgumentNullException("execute");
        _execute = execute;
        _canExecute = canExecute;
    }


    public event EventHandler CanExecuteChanged
    {
        add
        {

            if (_canExecute != null)
                CommandManager.RequerySuggested += value;
        }

        remove
        {

            if (_canExecute != null)
                CommandManager.RequerySuggested -= value;
        }
    }


    public Boolean CanExecute(Object parameter)
    {
        return _canExecute == null ? true : _canExecute();
    }

    public void Execute(Object parameter)
    {
        _execute();
    }
}

以下是ViewModel中命令的代码:

void DoThisWorkExecute()
    {
        // if Button1 is clicked...do this

        // if Button2 is clicked...do this
    }

    bool CanDoThisWorkExecute()
    {
        return true;
    }

    public ICommand ButtonCommand { get { return new RelayCommand(DoThisWorkExecute, CanDoThisWorkExecute); } }

1 个答案:

答案 0 :(得分:2)

您可以使用CommandParameter。这样的事情:

<Button Content="Open" Command="{Binding Path=ButtonCommand}" CommandParameter="Open"/>
<Button Content="Save" Command="{Binding Path=ButtonCommand}" CommandParameter="Save"/>

为此,您需要稍微不同的RelayCommand

实现
/// <summary>
/// https://gist.github.com/schuster-rainer/2648922 
/// Implementation from Josh Smith of the RelayCommand
/// </summary>
public class RelayCommand : ICommand
{
    #region Fields

    readonly Predicate<object> _canExecute;
    readonly Action<object> _execute;
    #endregion // Fields

    #region Constructors

    /// <summary>
    /// Initializes a new instance of the <see cref="RelayCommand"/> class.
    /// </summary>
    /// <param name="execute">The execute.</param>
    public RelayCommand(Action<object> execute)
        : this(execute, null)
    {
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="RelayCommand"/> class.
    /// </summary>
    /// <param name="execute">The execute.</param>
    /// <param name="canExecute">The can execute.</param>
    /// <exception cref="System.ArgumentNullException">execute</exception>
    public RelayCommand(Action<object> execute, Predicate<object> canExecute)
    {
        if (execute == null)
            throw new ArgumentNullException("execute");

        _execute = execute;
        _canExecute = canExecute;
    }
    #endregion // Constructors

    #region ICommand Members


    /// <summary>
    /// Occurs when changes occur that affect whether or not the command should execute.
    /// </summary>
    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    /// <summary>
    /// Defines the method that determines whether the command can execute in its current state.
    /// </summary>
    /// <param name="parameter">Data used by the command.  If the command does not require data to be passed, this object can be set to null.</param>
    /// <returns>true if this command can be executed; otherwise, false.</returns>
    public bool CanExecute(object parameter)
    {
        return _canExecute == null ? true : _canExecute(parameter);
    }
    /// <summary>
    /// Defines the method to be called when the command is invoked.
    /// </summary>
    /// <param name="parameter">Data used by the command.  If the command does not require data to be passed, this object can be set to null.</param>
    public void Execute(object parameter)
    {
        _execute(parameter);
    }

    #endregion // ICommand Members
}

但是:我没有询问单击了哪个按钮,而是为每个单独的动作创建一个Command(例如,打开,保存,退出)。重用命令(上下文菜单,KeyBinding,工具栏等)时,您将遇到更少的麻烦。你总是必须提供ui元素。这确实打破了MVVM模式。你真的必须摆脱旧的winforms方法,以便使用RelayCommand的全部力量。

我自己编写了一段代码片段,因此我不必编写所有代码。

<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets  xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
    <CodeSnippet Format="1.0.0">
        <Header>
            <Title>RelayCommand</Title>
            <Shortcut>RelayCommand</Shortcut>
            <Description>Code snippet for usage of the Relay Command pattern</Description>
            <Author>Mat</Author>
            <SnippetTypes>
                <SnippetType>Expansion</SnippetType>
            </SnippetTypes>
        </Header>
        <Snippet>
            <Declarations>
                <Literal>
                    <ID>name</ID>
                    <ToolTip>Name of the command</ToolTip>
                    <Default>Save</Default>
                </Literal>
            </Declarations>
            <Code Language="csharp">
                <![CDATA[   private RelayCommand _$name$Command;
        public ICommand $name$Command
        {
            get
            {
                if (_$name$Command == null)
                {
                    _$name$Command = new RelayCommand(param => this.$name$(param),
                        param => this.Can$name$(param));
                }
                return _$name$Command;
            }
        }

        private bool Can$name$(object param)
        {
            return true;
        }

        private void $name$(object param)
        {
            MessageServiceHelper.RegisterMessage(new NotImplementedException());
        }]]>
            </Code>
        </Snippet>
    </CodeSnippet>
</CodeSnippets>

另见https://msdn.microsoft.com/en-us/library/z41h7fat.aspx