TreeView中具有CompositeCollection的ContextMenu:菜单项消失

时间:2011-10-23 17:25:55

标签: wpf xaml

我有一个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 };

现在,如果在运行应用程序时,我打开项目“a”的上下文菜单,然后打开项目“b”,再打开项目“a”,我得到以下结果:

bug

我想我对CompositeCollection的使用引入了某种与数据模板不兼容的共享。有谁知道这里出了什么问题?

谢谢!

1 个答案:

答案 0 :(得分:2)

如果上下文菜单在上下文视觉中共享,则会更好地管理它们,前提是它们的基础项源是共享的菜单项列表(就像您的情况一样)。因此,基本上在您的情况下,上下文菜单应声明为静态资源,然后单独在所有文本块之间共享。

  <Window.Resources>
     ....
     <ContextMenu x:Key="MyContextMenu">
          <ContextMenu.ItemsSource>
             <CompositeCollection>
               <CollectionContainer
                   Collection="{StaticResource EditMenuItems}" />
               <Separator />
               <CollectionContainer
                   Collection="{StaticResource CommonMenuItems}" />
               </CompositeCollection>
          </ContextMenu.ItemsSource>
    </ContextMenu>
    <HierarchicalDataTemplate
            DataType="{x:Type local:ItemViewModel}"
            ItemsSource="{Binding Path=Children}">
       <TextBlock Text="{Binding Path=Name}"
                  ContextMenu="{StaticResource MyContextMenu}">
       ....
    </HierarchicalDataTemplate>  
  </Window.Resources>