代码之家  ›  专栏  ›  技术社区  ›  sflee

如何将命令绑定到动态上下文菜单

  •  0
  • sflee  · 技术社区  · 5 年前

    我使用c#、prism、wpf。我想在列表视图中动态创建一个上下文列表,如下图所示:

    enter image description here

    当我单击这些菜单项时,它将回调到我的自定义函数。在该函数中,我可以识别单击了哪个菜单项,例如,我可以获取菜单项的标题。

    我尝试添加一个命令标记并绑定到ICommand。但当我点击它时,没有任何反应。

    我读过网络上的不同示例,但它们从未同时显示xaml和viewmodel的实现。我想问一下怎么做?非常感谢你。

    在App.xaml.cs中:

    ViewModelLocationProvider.Register<MainWindowView, MainWindowViewModel>();
    

    以下是我的名字:

    <ListView Grid.Row="2"  ItemsSource="{Binding ServiceObjects}" ItemContainerStyle="{StaticResource LstBoxItemStyleNormal}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <Grid>
                    <TextBlock Text="{Binding ServiceName}">
                        <TextBlock.ContextMenu>
                            <ContextMenu ItemsSource="{Binding ContextMenuList}">
                                <ContextMenu.ItemTemplate>
                                    <HierarchicalDataTemplate>
                                        <MenuItem Header="{Binding MenuName}" Command="{Binding ConfirmButtonCommand}"/>
                                    </HierarchicalDataTemplate>
                                </ContextMenu.ItemTemplate>
                            </ContextMenu>
                        </TextBlock.ContextMenu>
                    </TextBlock>
                </Grid>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
    

    以下是我的视图模型:

    class MainWindowViewModel : BindableBase
    {
        public class MenuNode : BindableBase
        {
            private string _menuName;
            public string MenuName
            {
                get => _menuName;
                set => SetProperty(ref _menuName, value);
            }
        }
        public class ServiceNode : BindableBase
        {
            private string _serviceName;
            public string ServiceName
            {
                get => _serviceName;
                set => SetProperty(ref _serviceName, value);
            }
            public ObservableCollection<MenuNode> ContextMenuList { get; } = new ObservableCollection<MenuNode>();
        }
        public ObservableCollection<ServiceNode> ServiceObjects { get; } = new ObservableCollection<ServiceNode>();
        
        public MainWindowViewModel()
        {
            for (int i = 0; i < 10; i++)
            {
                ServiceNode tempNode = new ServiceNode { ServiceName = "AP", State = "Normal" };
                tempNode.ContextMenuList.Add(new MenuNode { MenuName = "A Item" });
                tempNode.ContextMenuList.Add(new MenuNode { MenuName = "B Item" });
                tempNode.ContextMenuList.Add(new MenuNode { MenuName = "C Item" });
                ServiceObjects.Add(tempNode);
            }
            ConfirmButtonCommand = new DelegateCommand(HandleConfirmButtonCommand);
        }
        public ICommand ConfirmButtonCommand { get; }
    
        private void HandleConfirmButtonCommand()
        {
            
        }
    
    1 回复  |  直到 5 年前
        1
  •  1
  •   Quercus    5 年前

    首先,绑定到 Command 对于 MenuItem 应该是花括号: {Binding ConfirmButtonCommand} .
    其次,您的命令定义在 MainWindowViewModel 类,而 DataContext 对于 菜单项 是 MenuNode ,因此找不到该命令。
    最简单的修复方法是-命名 List 当绑定到命令时,请参考其 数据上下文 .
    例如:

    <ListView x:Name="list" ...>
    

    然后

    <MenuItem Header="{Binding MenuName}" Command="{Binding DataContext.ConfirmButtonCommand, ElementName=list}"/>
    

    此外,对于命令,您可能还需要知道 ServiceNode 它被点击了,你可以通过 CommandParameter (取 数据上下文 从 ContextMenu 这是成立的 菜单项 ):

    <MenuItem ... CommandParameter="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType=ContextMenu}}">
    
        2
  •  0
  •   sflee    5 年前

    这是我最后使用的答案。谢谢

    在App.xaml.cs中:

    ViewModelLocationProvider.Register<MainWindowView, MainWindowViewModel>();
    

    以下是我的名字:

    <ListView Grid.Row="2"  ItemsSource="{Binding ServiceObjects}" ItemContainerStyle="{StaticResource LstBoxItemStyleNormal}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <Grid>
                    <TextBlock Text="{Binding ServiceName}" Tag="{Binding DataContext, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListView}}">
                        <TextBlock.ContextMenu>
                            <ContextMenu ItemsSource="{Binding ContextMenuList}">
                                <ContextMenu.ItemTemplate>
                                    <HierarchicalDataTemplate>
                                        <MenuItem Header="{Binding MenuName}"
                                                  Command="{Binding PlacementTarget.Tag.ConfirmButtonCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}}"
                                                  CommandParameter="Binding MenuName"/>
                                    </HierarchicalDataTemplate>
                                </ContextMenu.ItemTemplate>
                            </ContextMenu>
                        </TextBlock.ContextMenu>
                    </TextBlock>
                </Grid>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
    

    以下是我的视图模型:

    class MainWindowViewModel : BindableBase
    {
        public class MenuNode : BindableBase
        {
            private string _menuName;
            public string MenuName
            {
                get => _menuName;
                set => SetProperty(ref _menuName, value);
            }
        }
        public class ServiceNode : BindableBase
        {
            private string _serviceName;
            public string ServiceName
            {
                get => _serviceName;
                set => SetProperty(ref _serviceName, value);
            }
            public ObservableCollection<MenuNode> ContextMenuList { get; } = new ObservableCollection<MenuNode>();
        }
        public ObservableCollection<ServiceNode> ServiceObjects { get; } = new ObservableCollection<ServiceNode>();
        
        public MainWindowViewModel()
        {
            for (int i = 0; i < 10; i++)
            {
                ServiceNode tempNode = new ServiceNode { ServiceName = "AP", State = "Normal" };
                tempNode.ContextMenuList.Add(new MenuNode { MenuName = "A Item" });
                tempNode.ContextMenuList.Add(new MenuNode { MenuName = "B Item" });
                tempNode.ContextMenuList.Add(new MenuNode { MenuName = "C Item" });
                ServiceObjects.Add(tempNode);
            }
            ConfirmButtonCommand = new DelegateCommand<string>(HandleConfirmButtonCommand);
        }
        public ICommand ConfirmButtonCommand { get; }
    
        private void HandleConfirmButtonCommand(string parameter)
        {
            
        }