2010-09-19 18 views
2

j'ai une liste avec différentes catégories d'articles. DataTemplates sont utilisés pour présenter ces objets de la manière appropriée. Je veux avoir différents menus contextuels dans les DataTemplates de ces classes.ContextMenu sur ListBox article avec DataTemplate

Tout fonctionne bien avec la souris, mais en utilisant le clavier, je ne peux pas faire apparaître le menu contextuel.

Ceci est probablement parce que le clavier de mise au point ne figure pas sur le contenu du DataTemplate, mais sur le ListBoxItem.

Comment puis-je obtenir le ListBoxItem de se référer à ContextMenu du contenu?

Exemple de code:

<Window x:Class="WpfApplication8.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:my="clr-namespace:WpfApplication8" 
    Title="MainWindow" Height="350" Width="525"> 
<Window.Resources> 
    <DataTemplate DataType="{x:Type my:Orange}"> 
     <TextBlock> 
      Orange 
      <TextBlock.ContextMenu> 
       <ContextMenu> 
        <MenuItem Header="Peel"/> 
       </ContextMenu> 
      </TextBlock.ContextMenu> 
     </TextBlock> 
    </DataTemplate> 
    <DataTemplate DataType="{x:Type my:Apple}"> 
     <TextBlock> 
      Apple 
      <TextBlock.ContextMenu> 
       <ContextMenu> 
        <MenuItem Header="Uncore"/> 
       </ContextMenu> 
      </TextBlock.ContextMenu> 
     </TextBlock> 
    </DataTemplate> 
</Window.Resources> 
<Grid> 
    <ListBox ItemsSource="{Binding Fruits}"/> 
</Grid> 
</Window> 


using System.Windows; 
using System.Collections.ObjectModel; 

namespace WpfApplication8 
{ 
    public partial class MainWindow : Window 
    { 
     public MainWindow() 
     { 
      InitializeComponent(); 
      Fruits = new ObservableCollection<Fruit>(); 
      Fruits.Add(new Apple()); 
      Fruits.Add(new Apple()); 
      Fruits.Add(new Orange()); 
      this.DataContext = this; 
     } 

     public ObservableCollection<Fruit> Fruits { get; set; } 
    } 

    public class Fruit 
    { 
    } 

    public class Apple : Fruit 
    { 
    } 

    public class Orange : Fruit 
    { 
    } 
} 

Répondre

0

J'ai trouvé une solution. Dans le code-behind je donnerai à chaque ListBoxItem le menu contextuel que je trouve de ses enfants visuels.

Il me donne la possibilité d'ajouter des menus contextuels aux DataTemplates pour les différentes classes, me donnant ainsi le polymorphisme me plaît. Je préfère aussi déclarer les menus en XAML. Et cela fonctionne avec la navigation au clavier, ainsi que l'utilisation de la souris.

Le code aurait probablement pu être mis dans une propriété attachée ou quelque chose pour l'élégance.

ajouter un gestionnaire d'événements chargé et ce code:

void MainWindow_Loaded(object sender, RoutedEventArgs e) 
    { 
     foreach (var item in list.Items) 
     { 
      ListBoxItem lbItem = list.ItemContainerGenerator.ContainerFromItem(item) as ListBoxItem; 
      lbItem.ContextMenu = FindContextMenu(lbItem); 
     } 
    } 

    private ContextMenu FindContextMenu(DependencyObject depObj) 
    { 
     ContextMenu cm = depObj.GetValue(ContextMenuProperty) as ContextMenu; 
     if (cm != null) 
      return cm; 
     int children = VisualTreeHelper.GetChildrenCount(depObj); 
     for (int i = 0; i < children; i++) 
     { 
      cm = FindContextMenu(VisualTreeHelper.GetChild(depObj, i)); 
      if(cm != null) 
       return cm; 
     } 
     return null; 
    } 
1

Ce gars ont le même problème que vous: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/5737a331-2014-4e39-b87c-215ae6a7cdd4.

au lieu de se battre avec mise au point, ajouter un menu contextuel pour la zone de liste. Ajoutez un gestionnaire d'événement ContextMenuOpening à votre zone de liste. Dans ce gestionnaire, en fonction du contexte de données de l'élément actuellement sélectionné, ajoutez les menuitems dont vous avez besoin par programmation.

+0

Un menu contextuel de la zone de liste ouvre au milieu de la zone de liste, non où l'élément sélectionné est. De plus, j'aimerais déclarer les éléments du menu contextuel dans XAML, ce qui rend la mondialisation plus facile que de le mettre dans du code. L'accentuation du clavier est primordiale pour les utilisateurs malvoyants ou les utilisateurs qui, pour d'autres raisons, évitent les souris. – Guge

3

moi aussi eu ce problème. Lecture Bea Stollnitz' blog m'a donné une idée.

J'ai commencé avec un modèle de données comme dans mes ressources:

<ContextMenu x:Key="MyMenu"> 
    <MenuItem Header="A" /> 
    <MenuItem Header="B" /> 
    <MenuItem Header="C" /> 
</ContextMenu> 

<DataTemplate x:Key="MyTemplateKey" DataType="{x:Type local:myType}"> 
    <TextBlock ContextMenu="{StaticResource MyMenu}" > 
     <Run Text="{Binding Path=MyBindingPath}" FontSize="20" FontWeight="Bold" /> 
    </TextBlock> 
</DataTemplate> 

Comme décrit ci-dessus, cela provoque la touche de menu du clavier ne pas invoquer le menu contextuel, bien que clic droit fonctionne. Le problème est le menu contextuel doit être sur le ListBoxItem, pas le modèle à l'intérieur.

Hey presto!

<Style x:Key="ContextLBI" TargetType="{x:Type ListBoxItem}"> 
    <Setter Property="ContextMenu" Value="{StaticResource MyMenu}"> 

    </Setter> 
</Style> 

Maintenant, il suffit de retirer le ContextMenu à partir du modèle de données et définir votre style sur votre liste comme ceci:

<ListBox ItemTemplate="{StaticResource MyTemplateKey}" 
     ItemContainerStyle="{StaticResource ContextLBI}" 
... > 
</ListBox>