我试图动态显示与TreeViewItem相关的菜单和子菜单,但我发现了一个奇怪的行为:我第一次右键单击节点,菜单和子菜单显示正确,然后如果我按下escape然后我重复右键单击节点,子菜单消失。之后,有时子菜单会随机出现或消失。
我将错误减少到以下代码(它是重现错误的最小代码)。有谁知道我如何纠正代码?我一直在找天,但我找不到任何解决方案。
谢谢。
.Net framework 4.6.1和4.7
MainWindow.xaml
sess.run(x_batch)
MainWindow.xaml.cs
<Window x:Class="WpfTester.TestWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfTester"
mc:Ignorable="d"
Title="Window" Height="300" Width="300">
<Grid>
<TreeView HorizontalContentAlignment="Stretch">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:MyMenu}" ItemsSource="{Binding Commands}">
<TextBlock Text="{Binding Name}" Background="Blue" />
</HierarchicalDataTemplate>
</TreeView.Resources>
<TreeViewItem Header="Level 1" IsExpanded="True" ContextMenuOpening="OnContextMenuOpening">
<TreeViewItem.ContextMenu>
<ContextMenu>
<ContextMenu.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Command" Value="{Binding}" />
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
</TreeViewItem.ContextMenu>
</TreeViewItem>
</TreeView>
</Grid>
注意:感谢Rowbear我找到了最佳解决方案。
MainWindow.xaml
public partial class TestWindow : Window
{
public TestWindow()
{
InitializeComponent();
}
private void OnContextMenuOpening(object sender, ContextMenuEventArgs args)
{
((TreeViewItem)sender).ContextMenu.ItemsSource = GetCommands();
}
private static IEnumerable<MyMenu> GetCommands()
{
return new MyMenu[]
{
new MyMenu("Pep", new[]
{
new MyMenu("x"),
new MyMenu("y"),
new MyMenu("z"),
}),
new MyMenu("fuz")
};
}
}
public class MyMenu : ICommand
{
public MyMenu(string name)
{
this.Name = name;
}
public MyMenu(string name, IEnumerable<MyMenu> items)
{
this.Name = name;
items.ToList().ForEach(x => this.commands.Add(x));
}
public string Name { get; }
public ObservableCollection<MyMenu> Commands
{
get { return this.commands; }
}
private readonly ObservableCollection<MyMenu> commands = new ObservableCollection<MyMenu>();
public virtual bool CanExecute(object parameter)
{
return true;
}
public virtual void Execute(object parameter)
{
}
public event EventHandler CanExecuteChanged;
}
IsInstanceOfTypeConverter.cs
<Window x:Class="WpfTester.TestWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfTester"
mc:Ignorable="d"
Title="Window" Height="300" Width="300">
<Grid>
<TreeView HorizontalContentAlignment="Stretch">
<TreeView.Resources>
<local:IsInstanceOfTypeConverter x:Key="IsInstanceOfTypeConverter" />
</TreeView.Resources>
<TreeViewItem Header="Level 1" IsExpanded="True" ContextMenuOpening="OnContextMenuOpening">
<TreeViewItem.ContextMenu>
<ContextMenu>
<ContextMenu.ItemContainerStyle>
<!-- Style for MenuItem -->
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Header" Value="{Binding Name}" />
<Setter Property="ToolTip" Value="{Binding Name}" />
<Setter Property="Command" Value="{Binding}" />
<Style.Triggers>
<!-- Style for MyMenu -->
<DataTrigger Binding="{Binding Converter={StaticResource IsInstanceOfTypeConverter},
ConverterParameter={x:Type local:MyMenu}}"
Value="True">
<Setter Property="ItemsSource" Value="{Binding Commands}"/>
<Setter Property="Background" Value="Blue" />
</DataTrigger>
<!-- More types of menus and commands with different binding.. -->
<DataTrigger Binding="{Binding Converter={StaticResource IsInstanceOfTypeConverter},
ConverterParameter={x:Type local:MyMenu2}}"
Value="True">
<Setter Property="ItemsSource" Value="{Binding Actions}"/>
<Setter Property="Background" Value="Green" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
</TreeViewItem.ContextMenu>
</TreeViewItem>
</TreeView>
</Grid>
答案 0 :(得分:0)
你正在做一些奇怪的事情,你依赖于ContextMenu的ItemsSource作为菜单项的顶级列表,但后来依靠hierarchydatatemplate来构建一个树。也许它在某些情况下会起作用 - 我没有尝试过这种策略。但是,将演示代码的xaml更改为以下内容可以使您获得所需内容:
<Grid>
<TreeView HorizontalContentAlignment="Stretch">
<TreeViewItem Header="Level 1" IsExpanded="True" ContextMenuOpening="OnContextMenuOpening">
<TreeViewItem.ContextMenu>
<ContextMenu>
<ContextMenu.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Header" Value="{Binding Name}"></Setter>
<Setter Property="Command" Value="{Binding}" />
<Setter Property="Background" Value="Blue"></Setter>
<Setter Property="ItemsSource" Value="{Binding Commands}"></Setter>
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
</TreeViewItem.ContextMenu>
</TreeViewItem>
</TreeView>
</Grid>
这里我依靠MenuItem的ItemsSource来创建我的子菜单项。