У меня есть TreeView, который будет содержать много разных видов узлов дерева с контекстными меню. Контекстные меню для разных типов узлов дерева будут отличаться, но также будут разделять некоторые разделы. Я хочу определить общие разделы меню только один раз. Поэтому я определяю некоторые общие массивы пунктов меню как ресурс, а затем перетаскиваю их в каждое контекстное меню, используя CompositeCollection. Очень простой пример моего сценария выглядит следующим образом:
<Window x:Class="TreeViewCompositeContextMenuProblem.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TreeViewCompositeContextMenuProblem"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<x:Array x:Key="EditMenuItems" Type="{x:Type MenuItem}">
<MenuItem Header="Copy" />
<MenuItem Header="Paste" />
<MenuItem Header="Delete" />
</x:Array>
<x:Array x:Key="CommonMenuItems" Type="{x:Type MenuItem}">
<MenuItem Header="View properties" />
</x:Array>
<HierarchicalDataTemplate DataType="{x:Type local:ItemViewModel}" ItemsSource="{Binding Path=Children}">
<TextBlock Text="{Binding Path=Name}">
<TextBlock.ContextMenu>
<ContextMenu>
<ContextMenu.ItemsSource>
<CompositeCollection>
<CollectionContainer Collection="{StaticResource EditMenuItems}" />
<Separator />
<CollectionContainer Collection="{StaticResource CommonMenuItems}" />
</CompositeCollection>
</ContextMenu.ItemsSource>
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
</HierarchicalDataTemplate>
</Window.Resources>
<Grid>
<TreeView Name="treeView">
</TreeView>
</Grid>
</Window>
где ItemViewModel просто определяется как
public class ItemViewModel
{
public ObservableCollection<ItemViewModel> Children {get; set; }
public string Name {get;set;}
public ItemViewModel(string name)
{
Children = new ObservableCollection<ItemViewModel>();
Name = name;
}
}
Затем я связываю treeView следующим образом:
var vm = new ItemViewModel("root");
var a = new ItemViewModel("a");
var b = new ItemViewModel("b");
var c = new ItemViewModel("c");
vm.Children.Add(a);
vm.Children.Add(b);
b.Children.Add(c);
treeView.ItemsSource = new List<ItemViewModel>() { vm };
Теперь, если при запуске приложения я открываю контекстное меню для элемента «а», затем для элемента «б» и затем снова для элемента «а», я получаю следующий результат:
Я полагаю, что мое использование CompositeCollection вводит некоторый вид обмена, который не очень хорошо работает с шаблонами данных. Кто-нибудь знает, что здесь не так?
Спасибо!