我的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); } }
答案 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>