2017-10-14 6 views
0

Considérons un ListBox qui peut ne pas être complètement rempli avec ListBoxItems lors de l'exécution. Je veux personnaliser le ContextMenu pour ce ListBox selon si l'utilisateur clique avec le bouton droit sur l'un des ListBoxItems ou sur l'espace vide où aucun élément n'existe.Comment personnaliser un ContextMenu pour un ListBox wpf

Le problème que je rencontre est que dans ce dernier cas, aucun événement ListBox n'est déclenché, seul l'événement ContextMenuOpening est déclenché. Et à partir de cet événement, je ne peux pas comprendre comment vérifier si l'utilisateur a cliqué sur un ListBoxItem existant ou non.

J'ai regardé toutes les propriétés et les événements de ListBox, mais je ne peux pas proposer une approche qui différencie ces deux cas. J'ai envisagé d'utiliser des déclencheurs de style mais, encore une fois, le problème principal est qu'un clic droit dans l'espace vide ne déclenche aucun événement ListBox. J'ai également passé en revue les liens que SO suggère mais aucun ne parle à cette question.

Comment cela peut-il être fait?

+0

Pourriez-vous donner un code pour expliquer votre question plus clairement? – Iron

+0

Pourriez-vous montrer la logique que vous utilisez et les événements auxquels votre logique est connectée? Vous pouvez créer deux ressources de ContextMenu et les utiliser dans ListBox.ContextMenu et ListBoxItem.ContextMenu. – Redouane

+0

@Iron Il ne s'agit pas d'une question de codage, mais plutôt d'une question conceptuelle: comment détecter ce que l'on clique sur un clic droit dans un ListBox partiellement rempli. Si j'avais du code, je l'aurais montré. Mais voir ma solution ci-dessous. – SezMe

Répondre

0

J'ai conçu une solution qui n'est pas jolie mais qui fonctionne. En gros, chaque fois que le ListBox perd le focus, je forcer à avoir rien sélectionné en réglant

ListBox.SelectedIndex = -1 

Maintenant, en cas ContextMenuOpening lorsque l'accent est de retour à la zone de liste, il est possible d'obtenir l'obtenir le ListBox.SelectedIndex et si c'est -1 alors l'utilisateur a cliqué dans la partie vide du ListBox sinon un ListBoxItem a été cliqué dessus.

Le codage de cette logique est simple.

0

Peut-être que je n'ai pas votre intention: Vous pouvez définir différents ContextMenu soit dans XAML ou Code-behind comme ceci:

XAML:

<ListBox PreviewMouseDown="ListBox_PreviewMouseDown"> 
    <ListBox.ItemContainerStyle> 
     <Style TargetType="{x:Type ListBoxItem}"> 
      <Setter Property="Template"> 
       <Setter.Value> 
        <ControlTemplate TargetType="{x:Type ListBoxItem}"> 
         <ContentPresenter> 
          <ContentPresenter.ContextMenu> 
           <ContextMenu> 
            <MenuItem Header="ListBoxItem"></MenuItem> 
            <MenuItem Header="ListBoxItem"></MenuItem> 
            <MenuItem Header="ListBoxItem"></MenuItem> 
           </ContextMenu> 
          </ContentPresenter.ContextMenu> 
         </ContentPresenter> 
        </ControlTemplate> 
       </Setter.Value> 
      </Setter> 
     </Style> 
    </ListBox.ItemContainerStyle> 
    <ListBoxItem>Item1</ListBoxItem> 
    <ListBoxItem>Item2</ListBoxItem> 
    <ListBoxItem>Item2</ListBoxItem> 
    <ListBoxItem>Item2</ListBoxItem> 
    <ListBox.ContextMenu> 
     <ContextMenu> 
      <MenuItem Header="ListBox"></MenuItem> 
      <MenuItem Header="ListBox"></MenuItem> 
      <MenuItem Header="ListBox"></MenuItem> 
     </ContextMenu> 
    </ListBox.ContextMenu> 
</ListBox> 

code-behind:

private void ListBox_PreviewMouseDown(object sender, MouseButtonEventArgs e) 
{ 
    if(e.ChangedButton == MouseButton.Right) 
    { 
     var listBoxItem = e.Source as ListBoxItem; 
     if (listBoxItem != null) 
     { 
      // clicked on ListBoxItem, customize the ContextMenu 
     } 

     var listBox = e.Source as ListBox; 
     if (listBox != null) 
     { 
      // clicked on ListBox, customize the ContextMenu 
     } 
    } 
} 
0

Voici une approche plus concise pour définir deux ContextMenu différents pour ListBox et ses ListBoxItem sans avoir à tout code-behind vérification, il fonctionne comme un charme:

<ListBox ContextMenu="{StaticResource ListContextMenu}"> 
    <ListBox.Resources> 
     <!-- Context Menu when right click on selected List Item --> 
     <ContextMenu x:Key="ItemContextMenu"> 
      <MenuItem Header="Eat"></MenuItem> 
      <MenuItem Header="Delete"></MenuItem> 
      <Separator></Separator> 
      <MenuItem Header="Send To Friend"></MenuItem> 
     </ContextMenu> 
     <!-- Context Menu when right click on listbox space --> 
     <ContextMenu x:Key="ListContextMenu"> 
      <MenuItem Header="Save Fruits"></MenuItem> 
      <MenuItem Header="Add Or Remove Fruits"></MenuItem> 
     </ContextMenu> 
     <!-- Applying Context Menu to ListBoxItem with Style --> 
     <Style TargetType="{x:Type ListBoxItem}"> 
      <Setter Property="ContextMenu" Value="{StaticResource ItemContextMenu}"> 
      </Setter> 
     </Style> 
    </ListBox.Resources> 

    <ListBox.ContextMenu> 
     <Binding Source="{StaticResource ListContextMenu}"></Binding> 
    </ListBox.ContextMenu> 


    <ListBoxItem>Banana</ListBoxItem> 
    <ListBoxItem>Apple</ListBoxItem> 
    <ListBoxItem>Orange</ListBoxItem> 
</ListBox> 

Si vous souhaitez modifier le contenu de ListBoxItem.ContextMenu dynamiquement en fonction de l'élément sélectionné, vous pouvez brancher un gestionnaire pour l'événement ContextMenu.Opened et que gestionnaire vous vérifiez l'élément sélectionné et ajouter une nouvelle MenuItem Collection à votre ContextMenu dans le code.

Notez que ces deux ContextMenu s seront affichés uniquement à l'intérieur de ce ListBox parce qu'ils sont définis dans ListBox.Resources.