Pass command parameter to method in ViewModel in WPF?

140,691

Solution 1

"ViewModel" implies MVVM. If you're doing MVVM you shouldn't be passing views into your view models. Typically you do something like this in your XAML:

<Button Content="Edit" 
        Command="{Binding EditCommand}"
        CommandParameter="{Binding ViewModelItem}" >

And then this in your view model:

private ViewModelItemType _ViewModelItem;
public ViewModelItemType ViewModelItem
{
    get
    {
        return this._ViewModelItem;
    }
    set
    {
        this._ViewModelItem = value;
        RaisePropertyChanged(() => this.ViewModelItem);
    }
}

public ICommand EditCommand { get { return new RelayCommand<ViewModelItemType>(OnEdit); } }
private void OnEdit(ViewModelItemType itemToEdit)
{
    ... do something here...
}

Obviously this is just to illustrate the point, if you only had one property to edit called ViewModelItem then you wouldn't need to pass it in as a command parameter.

Solution 2

Just using Data Binding syntax. For example,

<Button x:Name="btn" 
         Content="Click" 
         Command="{Binding ClickCmd}" 
         CommandParameter="{Binding ElementName=btn,Path=Content}" /> 

Not only can we use Data Binding to get some data from View Models, but also pass data back to View Models. In CommandParameter, must use ElementName to declare binding source explicitly.

Solution 3

If you are that particular to pass elements to viewmodel You can use

 CommandParameter="{Binding ElementName=ManualParcelScanScreen}"

Solution 4

Try this:

 public class MyVmBase : INotifyPropertyChanged
{
  private ICommand _clickCommand;
   public ICommand ClickCommand
    {
        get
        {
            return _clickCommand ?? (_clickCommand = new CommandHandler( MyAction));
        }
    }
    
       public void MyAction(object message)
    {
        if(message == null)
        {
            Notify($"Method {message} not defined");
            return;
        }
        switch (message.ToString())
        {
            case "btnAdd":
                {
                    btnAdd_Click();
                    break;
                }

            case "BtnEdit_Click":
                {
                    BtnEdit_Click();
                    break;
                }

            default:
                throw new Exception($"Method {message} not defined");
                break;
        }
    }
}

  public class CommandHandler : ICommand
{
    private Action<object> _action;
    private Func<object, bool> _canExecute;

    /// <summary>
    /// Creates instance of the command handler
    /// </summary>
    /// <param name="action">Action to be executed by the command</param>
    /// <param name="canExecute">A bolean property to containing current permissions to execute the command</param>
    public CommandHandler(Action<object> action, Func<object, bool> canExecute)
    {
        if (action == null) throw new ArgumentNullException(nameof(action));
        _action = action;
        _canExecute = canExecute ?? (x => true);
    }
    public CommandHandler(Action<object> action) : this(action, null)
    {
    }

    /// <summary>
    /// Wires CanExecuteChanged event 
    /// </summary>
    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    /// <summary>
    /// Forcess checking if execute is allowed
    /// </summary>
    /// <param name="parameter"></param>
    /// <returns></returns>
    public bool CanExecute(object parameter)
    {
        return _canExecute(parameter);
    }

    public void Execute(object parameter)
    {
        _action(parameter);
    }
    public void Refresh()
    {
        CommandManager.InvalidateRequerySuggested();
    }
}

And in xaml:

     <Button
    Command="{Binding ClickCommand}"
    CommandParameter="BtnEdit_Click"/>
Share:
140,691

Related videos on Youtube

Mahsa
Author by

Mahsa

Updated on November 05, 2021

Comments

  • Mahsa
    Mahsa over 2 years

    I am trying to pass CommandParameter to the method in my ViewModel. How to do this?

    private void Open(object sender)
    {
        if (sender==this.objMainWindow.btnHistory)
        {
            objMainWindow.Container.Child = objHistory;
        }
    
        if (sender == this.objMainWindow.btnNew_Item)
        {
            objMainWindow.Container.Child = objNewItem;
        }
    
        if (sender == this.objMainWindow.btnSide_Effects)
        {
            objMainWindow.Container.Child = objSideEffect;
        }
    }
    

    This is my meyhod in ViewModel that I want to pass CommandParameter. I use CommandParameter for button.

  • Mahsa
    Mahsa almost 9 years
    how to use RaisePropertyChanged()?
  • Mark Feldman
    Mark Feldman almost 9 years
    That's just the implementation of property change notification MVVM Lite uses which you can add via NuGet (derive your view model from ViewModelBase). There are numerous other ways of doing it though including those shown here and here.
  • Mark Feldman
    Mark Feldman almost 5 years
    @marbel82 indeed I did, thanks for the correction (can't edit comments unfortunately).
  • Tyson Williams
    Tyson Williams over 4 years
    "if you only had one property to edit called ViewModelItem then you wouldn't need to pass it in as a command parameter". Regardless of the number of properties on the view model, I think the purpose of passing in the property value is to avoid the race condition that would otherwise occur (because the property could be mutated between the user clicking the button and the property being read some time after this click).
  • Mark Feldman
    Mark Feldman over 3 years
    @TysonWilliams correct me if I'm wrong, but I'm not sure that would actually be the case. In one scenario the command parameter is being fetched by the framework, in the other you're fetching it yourself in the handler. Both occur in the GUI thread, and after the "button press" itself. Any race condition that would occur in either of those scenarios would just as easily occur in the other. Command handling is generally not an atomic event, and even in async code the moment where the parameter is fetched is effectively the moment of the "button press".
  • Tyson Williams
    Tyson Williams over 3 years
    When passing in the parameter, there is no race condition. If in the handler you first do an async call and then fetch the parameter, it could be a different value than it would have if it had been passed in.
  • Mark Feldman
    Mark Feldman over 3 years
    Oh ok, if you've got an async handler then fair enough. Good point.