2016-11-14 161 views
0

我的WPF-App的主窗口上有很多按鈕。 這些按鈕的命令應該具有相同的實現/功能,但取決於按下哪個按鈕,函數訪問的文件/路徑發生了變化。 如何在不使用按鈕點擊事件處理程序(Windows窗體)的情況下檢測從ViewModel單擊哪個按鈕?檢測從ViewModel中點擊了哪個按鈕WPF

這裏是類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(); 
    } 
} 

下面是命令的視圖模型代碼:

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

你是如何實例化的按鈕?常見的MVVM方式是綁定XAML中的Command和CommandParameter,然後使用該參數來確定路徑。 – PMV

+0

字段'_execute'和'_canExecute'的定義有點不確定(MVVM指示燈?)。它應該是'Action '和'Func '。所以可以傳遞給ICommand方法的參數。 –

回答

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 
} 

但是:不要問哪個按鈕被點擊的,我會爲每個單獨的行動命令(例如打開,保存,退出)。重複使用命令(上下文菜單,工具欄等)時,您將遇到更少的麻煩。你將永遠不得不提供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