3

In a MVVM/WPF environment, I want to invoke a command (ComputeCommand) on the ViewModel when the SelectionChanged event of a ListView is raised. How can this be done, either in XAML or in C#?

Here is my command class. I have tried MainViewModel.Instance.MyCommand.Execute(); in the codebehind, but it's doesn't accept that.

public class ComputeCommand : ICommand
{
    public ComputeCommand(Action updateReport)
    {
        _executeMethod = updateReport;
    }

    Action _executeMethod;

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

    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    {
        _executeMethod.Invoke();
    }
}       
Marc
  • 12,706
  • 7
  • 61
  • 97
gsmida
  • 357
  • 1
  • 5
  • 15

4 Answers4

2

To answwer your question - you are missing a parameter. THis call should work:

MainViewModel.Instance.MyCommand.Execute(null);

However, you dont need an ICommand for that, this interface serves different purpose.

What you need is to either handle SelectionChanged on view side

var vm = DataContext as YourViewModelType;
if (vm != null)
{
    vm.Compute(); //some public method, declared in your viewmodel
}

or to handle it on viewmodel side by binding to IsSelected property of item container

Nikita B
  • 3,303
  • 1
  • 23
  • 41
  • I have tried bothe of solutions but none worked :/ I'm using MVVM because I have some data to be update on the screen at the moment of the execution – gsmida Mar 07 '13 at 09:35
  • What do you mean by "none worked"? They failed to compile? Failed to execute? With exception? Or what? – Nikita B Mar 07 '13 at 10:00
  • You cant bind event to an ICommand. You should replace it with SelectionChanged="SelectionChangedHandler" and then implement this handler in code behind the way i described above – Nikita B Mar 07 '13 at 10:11
2

I really recommend the use of a Mvvm framework like MVVM Light, so you can do something like this:

XAML:

xmlns:MvvmLight_Command="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras"
xmlns:Custom="clr-namespace:System.Windows.Interactivity;  assembly=System.Windows.Interactivity"

 <ListBox>
 ...
     <Custom:Interaction.Triggers>
          <Custom:EventTrigger EventName="SelectionChanged ">
             <MvvmLight_Command:EventToCommand PassEventArgsToCommand="False" Command="{Binding Path=ComputeCommand}"/>
          </Custom:EventTrigger>
     </Custom:Interaction.Triggers>

</Listbox>

ViewModel:

public RelayCommand ComputeCommand{ get; private set; }

This is IMO an elegant way to keep your events wiring clean and tidy.

D.Rosado
  • 5,634
  • 3
  • 36
  • 56
1

In general: To invoke a command when an event of a control is raised, you can use EventTriggers.

<ListView>
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="SelectionChanged" >
            <i:InvokeCommandAction Command="{Binding CommandToBindTo}" CommandParameter="{Binding CommandParameterToBindTo}" />
        </i:EventTrigger>
    </i:Interaction.Triggers>
</ListView>

To do this, you need to reference System.Windows.Interactivity.dll in your XAML:

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"

That being said, you should use a MVMM framework, for example MVVM to simplify the implementation of commands in general. It is not maintainable in the long run to have a single class for every command you need. A framework like MVVMLight or PRISM provides DelegateCommands which allow you to create new commands from delegates (methods on your ViewModel) directly.

Marc
  • 12,706
  • 7
  • 61
  • 97
0

First you have to define a binding for Command, so the function that have to be executed on the invokation of the command.

This can be done in XAML, like:

<CommandBinding Command="name_of_the_namespace:ComputeCommand" Executed="ComputeCommandHandler" />

After, you can, for example in some class initialize a command, like:

 public class AppCommands {
    public static readonly ICommand ComputeCommand = 
             new   RoutedCommand("ComputeCommand", typeof(AppCommands));
 }

and after can use it like:

 AppCommands.ComputeCommand.Execute(sender);

When you're dealing with WPF, so MVVM pattern, you need to write the much more code the usual, but benefit from flexibility of it.

Tigran
  • 61,654
  • 8
  • 86
  • 123