简体   繁体   中英

How do I get the child controls of a ListBox?

I have a ListBox in xaml which has a sub-ListBox inside the top-level ListBox's item template. Because the sub-ListBox is multi-select, and I can't bind the SelectedItems of the sub-ListBox to a viewmodel property for some reason, I'm trying to do a lot of this in the view code-behind.

I have everything working, except for one snag: I want to select all items in each sub-ListBox by default. Since the SelectedItems aren't data-bound, I'm trying to do it manually in code whenever a SelectionChanged event fires on the top-level ListBox. The problem is that I don't know how to get from the top-level ListBox to the sub-ListBox of the top-level selected item. I think I need to use the visual tree, but I don't know how to even get the dependency object that corresponds to the selected item.

Here's the code:

<ListBox ItemsSource="{Binding Path=Stuff}" SelectionChanged="StuffListBox_SelectionChanged" SelectedItem="{Binding Path=SelectedStuff, Mode=TwoWay}" telerik:RadDockPanel.Dock="Bottom">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <telerik:RadDockPanel>
            <TextBlock Text="{Binding Path=Name}" telerik:RadDockPanel.Dock="Top" />
                <ListBox ItemsSource="{Binding Path=SubStuff}" SelectionMode="Multiple" SelectionChanged="SubStuffListBox_SelectionChanged" Visibility="{Binding Converter={StaticResource StuffToSubStuffVisibilityConverter}}" telerik:RadDockPanel.Dock="Bottom">
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding Path=Name}" />
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                </ListBox>
            </telerik:RadDockPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

The converter ensures that only the selected top-level item has a visible sub-ListBox, and that's working.

I need to implement the following method:

private void StuffListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    ListBox stuffListBox = (ListBox)sender;

    foreach (Stuff stuff in e.AddedItems)
    {
        ...
        subStuffListBox.SelectAll();
    }
}

I tried doing stuffListBox.ItemContainerGenerator.ContainerFromItem(stuff) , but that always returns null. Even stuffListBox.ItemContainerGenerator.ContainerFromIndex(0) always returns null.

I also get strange behaviour from the selection changed method. ' e.AddedItems will contain items, but stuffListBox.SelectedItem is always null. Am I missing something?

From what I've read, my problem is coming from the fact that the containers haven't been generated at the time that I'm getting a selection change event. I've seen workarounds that involve listening for a the item container generator's status changed event, but I'm working in Silverlight and don't have access to that event. Is what I'm doing just not possible in Silverlight due to the oversight of making SelectedItems on a ListBox read-only?

Like you say this is probably best done in the ViewModel but you can select all the sub list items in code behind using VisualTreeHelper.

private void StuffListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
   var stuffListBox = (ListBox)sender;
        ListBoxItem item = (ListBoxItem)stuffListBox.ContainerFromItem(stuffListBox.SelectedItem);
        ListBox sublist = FindVisualChild<ListBox>(item);
        sublist.SelectAll();
}

FindVisualChild Method as per MSDN

private childItem FindVisualChild<childItem>(DependencyObject obj)
    where childItem : DependencyObject
{
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
    {
       DependencyObject child = VisualTreeHelper.GetChild(obj, i);
       if (child != null && child is childItem)
          return (childItem)child;
       else
       {
          childItem childOfChild = FindVisualChild<childItem>(child);
          if (childOfChild != null)
            return childOfChild;
       }
 }
 return null;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM