2011-10-23 5 views
1

J'ai un TreeView qui va contenir de nombreux types de nœuds d'arbre avec des menus contextuels. Les menus contextuels pour les différents types de nœuds d'arbres seront différents, mais partageront également certaines sections. Je veux seulement définir les sections du menu commun une fois. Je définis donc des tableaux communs d'éléments de menu en tant que ressource, puis les place dans chaque menu contextuel à l'aide d'une collection composite. Un exemple très simple de mon scénario est comme suit:ContextMenu avec CompositeCollection dans TreeView: les éléments de menu disparaissent

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

où le ItemViewModel est simplement défini comme

public class ItemViewModel 
{ 
    public ObservableCollection<ItemViewModel> Children {get; set; } 
    public string Name {get;set;} 

    public ItemViewModel(string name) 
    { 
     Children = new ObservableCollection<ItemViewModel>(); 
     Name = name; 
    } 
} 

Je lie alors le treeView comme suit:

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 }; 

Maintenant, si , lors de l'exécution de l'application, j'ouvre le menu contextuel sur le point "a", puis sur le point "b" puis sur le point "a" à nouveau, j'obtiens le résultat suivant:

bug

Je suppose que mon utilisation de CompositeCollection introduit un type de partage qui ne joue pas bien avec les modèles de données. Est-ce que quelqu'un sait ce qui ne va pas ici?

Merci!

Répondre

2

Les menus contextuels sont mieux gérés s'ils sont partagés parmi les visuels contextuels à condition que leur source d'éléments sous-jacents soit la liste partagée des éléments de menu (comme votre cas). Donc, dans votre cas, le menu contextuel doit être déclaré comme une ressource statique, puis partagé entre tous les blocs de texte individuellement.

<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

C'est un bon point - merci. Toutefois, il y aura toujours des problèmes si plusieurs menus contextuels utilisent les collections "EditMenuItems", car cela introduira le partage des éléments de menu individuels entre les menus. J'ai trouvé que l'ajout de x: Shared = "False" aux éléments x: Array aidé. Cela demande à l'analyseur XAML de copier les tableaux verbatim au lieu de les référencer. –

Questions connexes