Question

I've got some XAML like the following:

<UserControl x:Class="Foo">
  <UserControl.Resources>
    <ContextMenu x:Key="ContextMenu1">
      <MenuItem Header="Command 1a"/>
      <MenuItem Header="Command 1b"/>
    </ContextMenu>
    <ContextMenu x:Key="ContextMenu2">
      <MenuItem Header="Command 2a"/>
      <MenuItem Header="Command 2b"/>
    </ContextMenu>
  </UserControl.Resources>

  <DockPanel>
    <TreeView>
      <TreeView.Resources>
        <DataTemplate DataType="{x:Type Type1}">
          <StackPanel ContextMenu="{StaticResource ContextMenu1"}/>
        </DataTemplate>

        <DataTemplate DataType="{x:Type Type2}">
          <StackPanel ContextMenu="{StaticResource ContextMenu2"}/>
        </DataTemplate>
      </TreeView.Resources>
    </TreeView>
  </DockPanel>
</UserControl>

and a code behind similar to the following:

public class Type1 {
  public void OnCommand1a() {}
  public void OnCommand1b() {}
}

public class Type2 {
  public void OnCommand2a() {}
  public void OnCommand2b() {}
}

What do I need to do so that clicking the respective items on the menus calls the corresponding function?

If I add:

Command="{Binding Path=OnCommand1a}" CommandTarget="{Binding Path=PlacementTarget}"

etc then at runtime I get errors about how OnCommand1a is not a property. Some searching suggests this has something to do with a RoutedUIEvent, but I don't really understand what that's about.

If I use

Click="OnCommand1a" 

then it looks for OnCommand1a() on the UserControl instead of on the type that is bound to the DataTemplate.

What is the standard way of dealing this?

Was it helpful?

Solution

First of all you need a class that extends ICommand. You can use this:

public class DelegateCommand : ICommand
{
    private readonly Action<object> executeMethod = null;
    private readonly Func<object, bool> canExecuteMethod = null;

    public event EventHandler CanExecuteChanged
    {
        add { return; }
        remove { return; } 
    }

    public DelegateCommand(Action<object> executeMethod, Func<object, bool> canExecuteMethod)
    {
        this.executeMethod = executeMethod;
        this.canExecuteMethod = canExecuteMethod;
    }

    public bool CanExecute(object parameter)
    {
        if (canExecuteMethod == null) return true;
        return this.canExecuteMethod(parameter);
    }

    public void Execute(object parameter)
    {
        if (executeMethod == null) return;
        this.executeMethod(parameter);
    }
}

Then, in your class Type1 you have to declare this:

public DelegateCommand OnCommand1a {get; private set;}

and set it in your Type1 constructor in this way:

OnCommand1a = new DelegateCommand(c => Cmd1a(), null);

where Cmd1a is:

private void Cmd1a()
{
     //your code here
}

Finally, in your xaml:

Command="{Binding Path=OnCommand1a}"    
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top