ReactiveUI command binding + ContextMenu in resources =?

850 Views Asked by At

I have a ReactiveUserControl. In this I have a TreeView that uses the ContextMenus defined below. The Converter enables me to have different menus for different items types in the tree.

Now what I want to do is to use the code behind to do a reactiveui command binding for the MenuItems. But I cant access the XName of a MenuItem when the ContextMenu is in Resources.

And the question: How can I get a binding like this:

this.BindCommand(ViewModel, vm => vm.RunCommand, v => v.XNameOfAContexdtMenuItem);

To work with the MenuItems in each ContextMenu?

    <StackPanel x:Name="MainPanel">
    <StackPanel.Resources>
        <ContextMenu x:Key="Menu_1" >
            <MenuItem x:Name="Command_1" Header="Menu for ItemType_1 Command 1" Click="i_dont_want_to_use_this" />
            <MenuItem x:Name="Command_2" Header="Menu for ItemType_1 Command 2"/>
        </ContextMenu>
        <ContextMenu x:Key="Menu_2" >
            <MenuItem x:Name="Command_3" Header="Menu for ItemType_2 Command 3" />
            <MenuItem x:Name="Command_4" Header="Menu for ItemType_2 Command 4"/>
        </ContextMenu>
        <conv:ContextMenuConverter x:Key="ContextMenuConverter" 
                                        WorkerMenu="{StaticResource Menu_1}"
                                        JobMenu="{StaticResource Menu_2}"
                                       />
    </StackPanel.Resources>

I should also mention that if I put the ContextMenu in TreeView.Resources it is still not accessable, as soon as it is in any resources the XName cant be accessed from code behind.

1

There are 1 best solutions below

0
Robert Björklund On

So I did some testing and the best way I could find to do this is to not use ContextMenu in Resources but to use the "ViewModelViewHost" like the code below:

<TreeView x:Name="TheTreeView">                  
  <TreeView.ItemTemplate>
                <HierarchicalDataTemplate ItemsSource="{Binding ListOfItemType_2 }" DataType="{x:Type local:ItemType_1ViewModel}">
                    <rxui:ViewModelViewHost ViewModel="{Binding}"/>
                    <HierarchicalDataTemplate.ItemTemplate>
                        <HierarchicalDataTemplate DataType="{x:Type local:ItemType_2ViewModel }" >
                            <rxui:ViewModelViewHost ViewModel="{Binding}"/>
                        </HierarchicalDataTemplate>
                    </HierarchicalDataTemplate.ItemTemplate>
                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>
        </TreeView>

Code behind ReactiveUI binding for TreeView Items:

   public FunctionTreeView()
    {
        InitializeComponent();
        this.WhenActivated(
            dis =>
            {
                this.WhenAnyValue(x => x.ViewModel).BindTo(this, x => x.DataContext).DisposeWith(dis);
                this.OneWayBind(ViewModel, vm => vm.ItemType_1ViewModelList , x => x.TheTreeView.ItemsSource).DisposeWith(dis);
            });
    }

Then add the context menus in ItemType_1View and ItemType_2View this makes it possbile to use ReactiveUI bindings. The only drawback is that ItemType_1ViewModel and ItemType_2ViewModel need to have a reference to the command, the commands cannot be in the TreeView's ViewModel.

 <UserControl.ContextMenu>
    <ContextMenu>
        <MenuItem x:Name="MenuItem_RunCommand" Header="Run" />
        <MenuItem x:Name="MenuItem_InformationCommand" Header="Show Information"/>
    </ContextMenu>
</UserControl.ContextMenu>

And the code behind:

public ItemType_2View()
    {
         InitializeComponent();
         this.WhenActivated(dis =>
                {
                  this.BindCommand(ViewModel, vm => vm.RunCommand, v => v.MenuItem_RunCommand).DisposeWith(dis);
});

Also the Views need to be registred:

dependencyResolver.Register(() => new ItemType_1View (), typeof(IViewFor<ItemType_1ViewModel>));
dependencyResolver.Register(() => new ItemType_2View (), typeof(IViewFor<ItemType_2ViewModel>));

That is it, I think. I hope someone else finds this useful :)