【问题标题】:How to identify which button clicked? (MVVM)如何识别点击了哪个按钮? (MVVM)
【发布时间】:2017-07-24 07:05:00
【问题描述】:

继续沿着 MVVM 的路径前进,我来到了按钮命令。经过相当多的反复试验,我终于有了一个使用ICommandButton_Click 命令的工作示例。

我的问题是,现在我制作了一个通用事件,我无法获取单击了哪个按钮来对其应用一些逻辑。在我的示例中,我没有使用任何可以获取 Sender 信息的东西。通常像下面这样使用RoutedEventArgs:

Button button = (Button)sender;

这就是我目前所拥有的。

ICommand 类:

public class CommandHandler : ICommand
{
    private Action _action;
    private bool _canExecute;
    public CommandHandler(Action action, bool canExecute)
    {
        _action = action;
        _canExecute = canExecute;
    }

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

    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    {
        _action();
    }
}

以及执行操作的代码:

private ICommand _clickCommand;
public ICommand ClickCommand => _clickCommand ?? (_clickCommand = new CommandHandler(MyAction, _canExecute));

public ViewModelBase()
{
    _canExecute = true;            
}

public void MyAction()
{
    //Apply logic here to differentiate each button
}

还有 XAML,

<Button Command="{Binding ClickCommand}" Style="{StaticResource RedButtonStyle}">MyButton</Button>

当将相同的命令绑定到其他按钮时,我将如何识别正在单击的按钮?

【问题讨论】:

  • 只是好奇,为什么不直接使用 2 ICommands?
  • @XanderLuciano,我只是认为应用一些标准来区分方法中的按钮是这样做的方法。干杯
  • 很公平!大约一个月前我刚刚开始使用 MVVM,所以我理解必须调整你的想法的困难。祝你好运!
  • @XanderLuciano,感谢您的支持,干杯。

标签: c# wpf button mvvm


【解决方案1】:

您不应该将所有按钮绑定到同一个命令。只需为每个按钮执行不同的命令即可。

【讨论】:

  • 好的,我明白了,所以在这方面,它类似于非 MVVM 场景中的命名处理程序,但这样代码与视图分离。谢谢
【解决方案2】:

可能不应该,但如果你想要,你可以使用CommandParameter=""

应该只使用 2 个 ICommand。

XAML:

&lt;Button Command="{Binding ClickCommandEvent}" CommandParameter="Jack"/&gt;

视图模型:

public RelayCommand ClickCommandEvent { get; set; }

public SomeClass()
{
    ClickCommandEvent = new RelayCommand(ClickExecute);
}

public void ClickExecute(object param)
{
    System.Diagnostics.Debug.WriteLine($"Clicked: {param as string}");

    string name = param as string;
    if (name == "Jack")
        HighFive();
}

您的 RelayCommand 类将是 this boiler plate:

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

    #endregion

    #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
    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
}

【讨论】:

  • 感谢您的回答,为了学习,我将尝试这个,但我将在项目中使用单独的命令。干杯
  • 热爱热情!如果您遇到任何麻烦,请告诉我!一旦你掌握了它,你就会爱上 MVVM。你做过INotifyPropertyChanged 了吗?
  • 我喜欢这些东西。是的,我已经实现了INotifyPropertyChanged,我从DataGrid 及其所有异质开始,可以更新、添加新记录等,但仍然无法弄清楚如何使用Context.Menu 删除记录。所以我暂时离开它并开始使用按钮命令。我最害怕的是TreeView 和 MVVM。
  • 我喜欢从我的主应用程序中拉出一个部分并使其成为自己的视图是多么容易!我没有更改单个绑定,我只是向每个视图传递了一个相同数据上下文的实例,它就可以工作了!这是我的结果:i.imgur.com/UHGYi1T.gifv
  • 这看起来是一个有趣的项目!大概不该在这里聊天,想聊聊就开个包间吧。
【解决方案3】:

这会给你点击的Button

<Button Command="{Binding ClickCommand}" 
        CommandParameter="{Binding RelativeSource={RelativeSource Self}}"/>

【讨论】:

  • UV 为您提供有用的答案。干杯。
【解决方案4】:

这就是 WPF 依赖过多代码来执行简单操作的地方。我的意思是处理按钮点击的 30 行代码有点荒谬,但不知何故,我们说服自己这是一件“好事”,因为它遵循一种模式。

过多的代码就是过多的代码。没有理由这么复杂。

【讨论】:

  • 虽然每个按钮实例都不是 30 行代码……但在您的库中只有一次。由于应用程序数据的某些状态,您将如何处理禁用按钮?紧耦合的意大利面条代码就是紧耦合的意大利面条代码。
【解决方案5】:

有时不可避免地将多个命令指向同一个函数以重用相同的代码。我发现这种方法是识别已单击哪个控件的最简单方法。在 Xaml 中,我为两个按钮设置了 ElementName,如下所示:

      <Button Grid.Row="0"
              Grid.Column="0"
              Content="Read File"                  
              Command="{Binding ReadProButtonClick}"
              CommandParameter="{Binding ElementName=ReadFile}"/>          

      <Button Grid.Row="0"                  
              Grid.Column="1"
              Content="Batch Convert"                 
              Command="{Binding ReadProButtonClick}"
              CommandParameter="{Binding ElementName=BatchMode}"/>

然后在 ViewModel 中,我得到按钮的名称,如下所示:

 Private void ReadProButton(Object context) {           
        Controls.Button btnClicked = CType(context, System.Windows.Controls.Button)           
        processName = btnClicked.Name
        ...
 }

因此,processName 将是 BatchMode 或 ReadFile 取决于用户单击的内容。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-05
    • 1970-01-01
    • 1970-01-01
    • 2012-05-23
    • 2018-05-15
    • 2021-04-25
    • 2017-04-26
    相关资源
    最近更新 更多