c# - 检测从ViewModel WPF单击了哪个按钮

标签 c# wpf button mvvm

我的WPF应用程序的主窗口上有很多按钮。
这些按钮的命令应具有相同的实现/功能,但根据所按下的按钮,访问该功能的文件/路径会发生变化。
如何在不使用按钮单击事件处理程序(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); } }

最佳答案

您可以使用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
}

但是:我不问单击哪个按钮,而是对每个单独的操作(例如,打开,保存,退出)进行命令。重复使用命令(上下文菜单,KeyBinding,工具栏等)时,您的麻烦将大大减少。您将始终必须提供ui元素。这确实打破了MVVM模式。为了使用RelayCommand的全部功能,您实际上必须摆脱旧的winforms方法。

我为自己编写了一个代码段,因此不必编写所有代码。
<?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

关于c# - 检测从ViewModel WPF单击了哪个按钮,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40599788/

相关文章:

c# - 在 C# 中将 session 存储为公共(public)

c# - C# .NET Singleton 类中的静态方法是否会对性能或内存消耗产生负面影响?

c# - 在 Linq 中使用点分语法时,我可以访问 SelectMany 跳过的 "parent"吗?

button - 在 Swift 中更改 IBOutlet 的位置

c# - SelectedIndexchanged 在 Asp.net 中无法用于选择值

c# - WPF DataGrid,如果 CellEditEnding 事件中的 e.Cancel = true,则保持焦点在单元格上

wpf - 如何处理用户控件中的意外异常

wpf - 将 ListViewItem ContextMenu MenuItem 命令绑定(bind)到 ListView 的 ItemsSource 的 ViewModel

javascript - 根据小时数隐藏按钮

delphi - 如何创建带有下拉菜单的按钮?