首页 > 解决方案 > ReactiveUI 命令绑定 + 资源中的 ContextMenu =?

问题描述

我有一个 ReactiveUserControl。在这个我有一个使用下面定义的 ContextMenus 的 TreeView。转换器使我能够为树中的不同项目类型提供不同的菜单。

现在我想做的是使用后面的代码为 MenuItems 做一个响应式命令绑定。但是当 ContextMenu 在资源中时,我无法访问 MenuItem 的 XName。

还有一个问题:我怎样才能得到这样的绑定:

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

要使用每个 ContextMenu 中的 MenuItems?

    <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>

我还应该提到,如果我将 ContextMenu 放在 TreeView.Resources 中,它仍然无法访问,只要它位于任何资源中,就无法从后面的代码访问 XName。

标签: c#wpftreeviewreactiveuicommandbinding

解决方案


所以我做了一些测试,我能找到的最好方法是不在资源中使用 ContextMenu,而是使用“ViewModelViewHost”,如下面的代码:

<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>

TreeView 项的 ReactiveUI 绑定背后的代码:

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

然后在 ItemType_1View 和 ItemType_2View 中添加上下文菜单,这使得使用 ReactiveUI 绑定成为可能。唯一的缺点是ItemType_1ViewModel和ItemType_2ViewModel需要有对命令的引用,命令不能在TreeView的ViewModel中。

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

以及背后的代码:

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

还需要注册视图:

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

就是这样,我想。我希望其他人觉得这很有用:)


推荐阅读