Pass command parameter to method in ViewModel in WPF?
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"/>
Related videos on Youtube
Mahsa
Updated on November 05, 2021Comments
-
Mahsa over 2 years
I am trying to pass
CommandParameter
to the method in myViewModel
. 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 passCommandParameter
. I useCommandParameter
for button. -
Mahsa almost 9 yearshow to use RaisePropertyChanged()?
-
Mark Feldman almost 9 years
-
Mark Feldman almost 5 years@marbel82 indeed I did, thanks for the correction (can't edit comments unfortunately).
-
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 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 over 3 yearsWhen 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 over 3 yearsOh ok, if you've got an async handler then fair enough. Good point.