2009-07-25 9 views
5

J'ai un Expander dans le ItemTemplate d'un ListBox. Rend bien. Le problème que j'ai rencontré est que je voudrais que l'événement ListBox_SelectionChanged se déclenche lorsque l'expandeur est développé et/ou sélectionné. L'événement MouseDown ne semble pas atteindre le ListBox.Événements WPF Listbox + Expander

Ce dont j'ai besoin est SelectedIndex de la ListBox. Parce que le ListBox_SelectionChanged n'est pas déclenché, l'index est -1 et je ne peux pas déterminer quel élément a été sélectionné. L'événement ListBox_SelectionChanged est déclenché si un utilisateur clique sur le contenu de l'Expander après qu'il a été développé. Si elles ne cliquent que sur l'expandeur, l'événement n'est pas déclenché. Ceci est déroutant pour l'utilisateur car visuellement, ils pensent qu'ils ont déjà cliqué sur cet élément en cliquant sur l'entête Expander. J'ai besoin de l'élément ListBox sélectionné lorsque l'utilisateur développe l'Expander car, en ce qui concerne l'utilisateur, l'élément est maintenant sélectionné quand ce n'est pas le cas.

Des suggestions sur comment faire fonctionner ceci ou d'autres manières de déterminer le SelectedIndex de la zone de liste avec des expandeurs dedans?

Code simplifié pour référence:

<Window x:Class="WpfApplication3.Window1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="Window1" Height="300" Width="300" 
    Loaded="Window_Loaded"> 
    <Grid Name="Root"> 
     <ScrollViewer> 
      <ListBox SelectionChanged="ListBox_SelectionChanged" ItemsSource="{Binding}"> 
       <ItemsControl.ItemTemplate > 
        <DataTemplate> 
         <Border> 
          <Expander> 
           <Expander.Header> 
            <TextBlock Text="{Binding Path=Name}"/> 
           </Expander.Header> 
           <Expander.Content> 
            <StackPanel> 
             <TextBlock Text="{Binding Path=Age}"/> 
             <TextBlock Text="Line 2"/> 
             <TextBlock Text="Line 3"/> 
            </StackPanel> 
           </Expander.Content> 
          </Expander> 
         </Border> 
        </DataTemplate> 
       </ItemsControl.ItemTemplate> 
      </ListBox> 
     </ScrollViewer> 
    </Grid> 
</Window> 

classe simple pour Reliure:

public class Person 
{ 
    public string Name { 
     get; 
     set; 
    } 

    public int Age { 
     get; 
     set; 
    } 
} 

Création et peuplant les données pour la liaison:

private void Window_Loaded(object sender, RoutedEventArgs e) { 

    data = new ObservableCollection<Person>(); 

    data.Add(new Person { 
     Name = "One", 
     Age=10 
    }); 

    data.Add(new Person { 
     Name = "Two", 
     Age = 20 
    }); 

    data.Add(new Person { 
     Name = "Three", 
     Age = 30 
    }); 

    Root.DataContext = data; 
} 

C'est l'événement dont j'ai besoin (vraiment juste le SelectedIndex dont j'ai besoin)

private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { 
    ListBox box = (ListBox)sender; 

    // This value is not set because events from Expander are not bubbled up to fire SelectionChanged Event 
    int index = box.SelectedIndex; 
} 

Répondre

1

Une autre façon qui ne marche pas dépend de la IsSelected, vous pouvez brancher un événement déployé/d'extension au code derrière et utiliser le code suivant pour connaître l'indice ListBox sur lequel vous avez cliqué.

DependencyObject dep = (DependencyObject)e.OriginalSource; 

while ((dep != null) && !(dep is ListViewItem)) 
{ 
    dep = VisualTreeHelper.GetParent(dep); 
} 

if (dep == null) 
    return; 

int index = yourListBox.ItemContainerGenerator.IndexFromContainer(dep); 
4

Ce que vous vouliez, c'est que le contrôle Expander contrôle la sélection ListBox. Vous pouvez facilement l'archiver en définissant une liaison TwoWay sur la propriété IsExpanded de l'Expander vers le ListBoxItem immédiat sur lequel vous avez cliqué. MISE À JOUR: Si vous devez éviter le repli automatique lorsque vous sélectionnez un autre élément, définissez le mode de sélection Listbox sur multiple.

<ListBox SelectionMode="Multiple" 
+0

Ahh oui - c'est logique et ça marche! Merci. – IUnknown

+0

Cela fonctionne maintenant - mais avec un effet secondaire indésirable. Quand j'élargis un deuxième Expander, le premier s'effondre automatiquement. Y at-il un moyen de le faire sans automatiquement réduire l'élément développé précédent? – IUnknown

+0

Il suffit de faire SelectionMode = "Multiple" sur le ListBox –

0

Merci Jobi. C'est plutôt intelligent. Le trou de lapin de WPF devient de plus en plus profond.

Voici ce que je ne vous basant sur votre suggestion:

private void Expander_Expanded(object sender, RoutedEventArgs e) { 
    DependencyObject dep = (DependencyObject)sender; 

    while ((dep != null) && !(dep is ListBoxItem)) { 
     dep = VisualTreeHelper.GetParent(dep); 
    } 

    if (dep == null) 
     return; 

    int index = PersonList.ItemContainerGenerator.IndexFromContainer(dep); 

    PersonList.SelectedIndex = index; 
} 

private void Expander_Collapsed(object sender, RoutedEventArgs e) { 
    DependencyObject dep = (DependencyObject)sender; 

    while ((dep != null) && !(dep is ListBoxItem)) { 
     dep = VisualTreeHelper.GetParent(dep); 
    } 

    if (dep == null) 
     return; 

    int index = PersonList.ItemContainerGenerator.IndexFromContainer(dep); 

    if (PersonList.SelectedIndex == index) 
     PersonList.SelectedIndex = -1; 
} 

je devais changer ListViewItem à ListBoxItem (j'utilisais un ListBox).

En outre, j'ai utilisé l'index pour sélectionner ou désélectionner le ListBox.SelectedIndex. Cela me donne l'expérience que je cherchais.

  1. La première fois que quelqu'un développe un Expander, il sélectionne le ListBoxItem nouvellement développé.

  2. Si quelqu'un développe un autre Expander, le ListBoxItem précédent est désélectionné, mais reste développé, le ListBoxItem nouvellement développé est sélectionné.

  3. Si quelqu'un réduit un Expander sélectionné, le ListBoxItem est désélectionné.

  4. S'il existe plusieurs Expandeurs développés, quelqu'un réduit un expandeur ListBoxItem non sélectionné, le ListBoxItem sélectionné précédemment reste sélectionné.

Merci pour l'aide - Je pense que c'est un petit extrait de code très utile pour quiconque utilise Expanders dans un ListBox.

+0

cool .. Ouais pas seulement expander dans un DataTemplate Listbox .. Tout contrôle comme Button/checkbox ou tout ce que vous avez vraiment besoin de ce genre de hack. –

+0

Je pense que votre mot "hack" est plus approprié que mon travail "code snippet". Cette solution ci-dessus n'est pas très jolie - ça marche - mais pas jolie. Il devrait y avoir une solution plus élégante que le graphique visuel. – IUnknown