简体   繁体   中英

Passing parameters to MVVM Command

Does anyone knows how to pass parameters to Command using CommandHandler ? Let's assume I would like to pass string hard coded value from XAML. I know how to pass from XAML, but not how to handle it in MVVM code behind. The code below works fine if there is no need to pass any parameters.

public ICommand AttachmentChecked
{
    get
    {
        return _attachmentChecked ?? (_attachmentChecked = new CommandHandler(() => ExecuteAttachmentChecked(), CanExecuteAttachmentChecked()));
    }
}

private void ExecuteAttachmentChecked()
{        
}

private bool CanExecuteAttachmentChecked()
{
    return true;
}

CommandHandler:

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();
    }
}

You need to change two things

1.Change your Commandhandler to accept parameter

 public class CommandHandler : ICommand
{
    private Action<object> _action;
    private bool _canExecute;
    public CommandHandler(Action<object> action, bool canExecute)
    {
        _action = action;
        _canExecute = canExecute;
    }

    public bool CanExecute(object parameter)
    {
        return _canExecute;
    }

    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    {
        _action(parameter);
    }
}

2.Change the method to accept the CommandParameter :

public ICommand AttachmentChecked
{
    get
    {
        return _attachmentChecked ?? (_attachmentChecked = new CommandHandler(param => ExecuteAttachmentChecked(param), CanExecuteAttachmentChecked()));
    }
}

private void ExecuteAttachmentChecked(object param)
{
 //param will the value of `CommandParameter` sent from Binding
}

private bool CanExecuteAttachmentChecked()
{
    return true;
}

You should just write your string into CommandParameter:

<Button Command="{Binding NextCommand}" 
CommandParameter="Hello" 
Content="Next" />

and change from:

private Action _action;
private bool _canExecute;

to allow accept parameters:

readonly Action<object> _execute;        
readonly Predicate<object> _canExecute;

Assuming that you are using RelayCommand in parameter obj of method DoSmth will be "Hello":

public RelayCommand YourCommand { get; set; }
public YourViewModel()
{
    NextCommand = new RelayCommand(DoSmth);
}

private void DoSmth(object obj)
{
    Message.Box(obj.ToString()); 
}

This has already been answered but you may not know that there is some Frameworks around to avoid boilerplate code related to commands (and INotifyPropertyChanged) in MVVM.

One of the most famous is MVVM Light that will handle a few things for you.

Using this framework, this is how you handle a command with parameters :

(Note : We're going to create a command that changed the UserControl displayed, as the UserControl is the "main part" of the application)

1) In your ViewModel, define a RelayCommand with type of argument (in this case, a UserControl)

public RelayCommand<UserControl> changePageCommand { get; private set; }

2) Define the method to be binded to the command (simplified here)

public void navigate(UserControl nextPage)
{
    currentUserControl = nextPage; 
}

3) Bind your command to the method you just defined

changePageCommand = new RelayCommand<UserControl>((page) => navigate(page));

Your command is now all set up and ready to use in your XAML, let's say you want to switch page with menu selections for example...

4) Binding Command with parameter to Controls (XAML)

<Menu>
    <MenuItem Header="_Pages">
        <MenuItem Header="_Account"
                  Command="{Binding changePageCommand}"
                  CommandParameter="{Binding pageManager.accountPage}" />
        <MenuItem Header="_Profile"
                  Command="{Binding changePageCommand}"
                  CommandParameter="{Binding pageManager.profilePage}" />
    </MenuItem>
</Menu>

Note : pageManager is simply a class that initializes all my pages to their default states, there's obviously a reference to it in my ViewModel.

Hope this helps you or anyone passing by

The parameter is passed in the ICommand.Execute method, you just need to pass it through to your handler.

public class CommandHandler : ICommand
{
    private Action<object> _action;
    private bool _canExecute;
    public CommandHandler(Action<object> action, bool canExecute)
    {
        _action = action;
        _canExecute = canExecute;
    }

    public bool CanExecute(object parameter)
    {
        return _canExecute;
    }

    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    {
        _action(parameter);
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM