2011-10-23 42 views
1

我有一個TreeView,它將包含許多不同種類的帶有上下文菜單的樹節點。不同類型的樹節點的上下文菜單將有所不同,但也會共享某些節。我只想定義一次通用的菜單部分。因此,我將一些常用的菜單項數組定義爲資源,然後使用CompositeCollection將它們拉入每個上下文菜單。我的方案的一個非常簡單的例子如下:TreeView中具有CompositeCollection的ContextMenu:菜單項消失

<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的使用引入了一些與數據模板不兼容的共享。有人知道這裏出了什麼問題嗎?

謝謝!

回答

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> 
+3

這是一個很好的觀點 - 謝謝。但是,如果多個上下文菜單正在使用「EditMenuItems」集合,則仍然會出現問題,因爲這會引入跨菜單共享各個菜單項。我發現向x:Array元素添加x:Shared =「False」有幫助。這指示XAML解析器逐字複製數組,而不是引用它們。 –