继续沿着MVVM的路径前进,我来到了按钮命令。经过相当多的反复试验后,我终于得到了一个使用Button_Click
的{{1}}命令的工作示例。
我的问题是,现在我已经制作了一个通用事件,我无法点击哪个按钮来应用某些逻辑。在我的示例中,我没有使用任何可以获取ICommand
信息的地方。通常使用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();
}
}
和XAML,
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
}
在将同一命令绑定到其他按钮时,如何确定单击哪个按钮?
答案 0 :(得分:4)
你可能不应该,但如果你想要,你可以使用CommandParameter=""
你应该只使用2个ICommands。
XAML:
<Button Command="{Binding ClickCommandEvent}" CommandParameter="Jack"/>
视图模型:
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
}
答案 1 :(得分:3)
这会为您点击Button
:
<Button Command="{Binding ClickCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource Self}}"/>
答案 2 :(得分:2)
您不应该将所有按钮绑定到同一命令。只需为每个按钮指定一个不同的命令。
答案 3 :(得分:0)
这是WPF依靠太多代码来执行简单操作的地方。我的意思是说,用于处理按钮单击的30行代码有点荒谬,但由于某种原因,我们认为它是一种“好”东西,因为它遵循一种模式。
过多代码就是过多代码。没有理由要这么复杂。
答案 4 :(得分:0)
有时这不可避免地导致将多个命令定向到同一功能以重用相同的代码。我发现这种方法是确定已单击哪个控件的最简单方法。在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取决于用户单击的内容。