我有一个在运行时从集合构建的菜单。这一切都如图所示。
但是,如果菜单包含子项(Child1,Child2等),则永远不会调用ReactiveCommand MenuCommand 。
如果我从菜单中删除所有子项以使菜单只包含父项,则调用MenuCommand 。我是WPF的新手。我在示例应用程序中重新创建了该问题(下面的代码)。 VS中没有可见的绑定错误。
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainWindowViewModel();
}
}
public class Service
{
public Service(string menuHeading, string menuSubHeading)
{
MenuHeading = menuHeading;
MenuSubHeading = menuSubHeading;
}
public string MenuHeading { get; set; }
public string MenuSubHeading { get; set; }
}
public static class MenuBuilder
{
public static ReactiveList<MenuItem> Build(ReactiveList<Service> services)
{
ReactiveList<MenuItem> menuItems = new ReactiveList<MenuItem>();
foreach (var service in services)
{
AddOrUpdate(menuItems, service);
}
return menuItems;
}
private static void AddOrUpdate(ReactiveList<MenuItem> menu, Service service)
{
if (menu.Any((_ => _.Header.ToString() == service.MenuHeading)))
{
var item = menu.FirstOrDefault(x => x.Header.ToString() == service.MenuHeading);
item.Items.Add(new MenuItem() { Header = service.MenuSubHeading });
//if above line removed MenuCommand works
}
else
{
menu.Add(new MenuItem() { Header = service.MenuHeading });
var item = menu.FirstOrDefault(x => x.Header.ToString() == service.MenuHeading);
item.Items.Add(new MenuItem() { Header = service.MenuSubHeading });
//if above line removed MenuCommand works
}
}
}
public class MainWindowViewModel : ReactiveObject
{
public MainWindowViewModel()
{
MenuCommand = ReactiveCommand.Create<Object>(selectedItem => OnMenuItemSelected(selectedItem));
MenuCommand.Execute().Subscribe();
}
public ReactiveCommand<Object, Unit> MenuCommand { get; }
private ReactiveList<MenuItem> servicesMenu;
private ReactiveList<Service> Services = new ReactiveList<Service>()
{
new Service("Parent1", "Child1"),
new Service("Parent2", "Child1"),
new Service("Parent2", "Child2"),
};
public ReactiveList<MenuItem> ServicesMenu
{
get
{
if (servicesMenu == null)
{
servicesMenu = MenuBuilder.Build(Services);
return servicesMenu;
}
else
{
return servicesMenu;
}
}
}
private void OnMenuItemSelected(Object selectedItem)
{
//This method is only called when the menu does not contain any child items
}
}
<Grid>
<StackPanel Orientation="Vertical">
<Button Name="Button" Content="Button" Padding="5" HorizontalAlignment="Left"
Tag="{Binding RelativeSource={RelativeSource Self}, Path=DataContext}">
<Button.ContextMenu>
<ContextMenu x:Name="MainMenu" ItemsSource="{Binding ServicesMenu}"
DataContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
<ContextMenu.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Command"
Value="{Binding DataContext.MenuCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Button}}}" />
<Setter Property="CommandParameter"
Value="{Binding RelativeSource={RelativeSource Self}}" />
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
</Button.ContextMenu>
</Button>
</StackPanel>
</Grid>
在Glenn提出建议后更新了XAML
<Grid>
<StackPanel Orientation="Vertical">
<Button Name="Button" Content="Button" Padding="5" HorizontalAlignment="Left"
Tag="{Binding RelativeSource={RelativeSource Self}, Path=DataContext}">
<Button.ContextMenu>
<ContextMenu x:Name="MainMenu" ItemsSource="{Binding ServicesMenu}"
DataContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
<ContextMenu.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Header" Value="{Binding Header}" />
<Setter Property="Command" Value="{Binding Command}" />
<!--<Setter Property="Command" Value="{Binding MenuCommand}" /> was also tried-->
<Setter Property="CommandParameter" Value="{Binding}" />
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
</Button.ContextMenu>
</Button>
</StackPanel>
</Grid>
答案 0 :(得分:1)
我怀疑这是因为子项目放置目标不像您期望的那样是Button,它将是父MenuItem。
过去我解决这个问题的一种方法是使用MVVM方法来处理这些类型的菜单项。
为您的项目创建一个菜单项VM(您在上面称它们为Service)(类似于您已经在做的事情)。在VM中有一个Command属性,并将命令作为其构造函数的一部分传递。然后你可以从你的Item Container Style中做{Binding MenuCommand}。
也不要直接在ViewModel中创建MenuItem,而只是直接绑定到服务。我还建议您直接在服务中创建子服务作为ObservableCollection,然后在您的项容器中设置ItemsSource属性以绑定到您的服务的子子项。