如何将命令绑定到动态上下文菜单
How to bind command to dynamic context menu
我正在使用 c#、prism、wpf。我想在listview中动态创建context list,如下图:
当我单击这些菜单项时,将回调到我的自定义函数。在该函数中,我可以识别单击了哪个菜单项,例如,我可以获得菜单项的header。
我尝试添加命令标签并绑定到 ICommand。但是点进去没有反应
我从网上读过不同的例子,但他们从来没有同时显示 xaml 和 viewmodel 的实现。请问怎么办呢?非常感谢。
在App.xaml.cs中:
ViewModelLocationProvider.Register<MainWindowView, MainWindowViewModel>();
以下是我的xaml:
<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()
{
}
首先绑定到 Command
for MenuItem
应该是大括号:{Binding ConfirmButtonCommand}
.
第二,你的命令定义在MainWindowViewModel
class,而DataContext
for MenuItem
是MenuNode
,所以找不到命令。
最简单的修复是 - 给 List
命名,当绑定到命令时,参考它的 DataContext
.
例如:
<ListView x:Name="list" ...>
然后
<MenuItem Header="{Binding MenuName}" Command="{Binding DataContext.ConfirmButtonCommand, ElementName=list}"/>
此外,对于命令,您可能还需要知道单击了什么 ServiceNode
,您可以通过 CommandParameter
传递它(从 [= 获取 DataContext
25=] 包含 MenuItem
):
<MenuItem ... CommandParameter="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType=ContextMenu}}">
这是我最后使用的答案。谢谢
在App.xaml.cs中:
ViewModelLocationProvider.Register<MainWindowView, MainWindowViewModel>();
以下是我的xaml:
<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)
{
}
我正在使用 c#、prism、wpf。我想在listview中动态创建context list,如下图:
当我单击这些菜单项时,将回调到我的自定义函数。在该函数中,我可以识别单击了哪个菜单项,例如,我可以获得菜单项的header。
我尝试添加命令标签并绑定到 ICommand。但是点进去没有反应
我从网上读过不同的例子,但他们从来没有同时显示 xaml 和 viewmodel 的实现。请问怎么办呢?非常感谢。
在App.xaml.cs中:
ViewModelLocationProvider.Register<MainWindowView, MainWindowViewModel>();
以下是我的xaml:
<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()
{
}
首先绑定到 Command
for MenuItem
应该是大括号:{Binding ConfirmButtonCommand}
.
第二,你的命令定义在MainWindowViewModel
class,而DataContext
for MenuItem
是MenuNode
,所以找不到命令。
最简单的修复是 - 给 List
命名,当绑定到命令时,参考它的 DataContext
.
例如:
<ListView x:Name="list" ...>
然后
<MenuItem Header="{Binding MenuName}" Command="{Binding DataContext.ConfirmButtonCommand, ElementName=list}"/>
此外,对于命令,您可能还需要知道单击了什么 ServiceNode
,您可以通过 CommandParameter
传递它(从 [= 获取 DataContext
25=] 包含 MenuItem
):
<MenuItem ... CommandParameter="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType=ContextMenu}}">
这是我最后使用的答案。谢谢
在App.xaml.cs中:
ViewModelLocationProvider.Register<MainWindowView, MainWindowViewModel>();
以下是我的xaml:
<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)
{
}