mj_
mj_

Reputation: 6447

Get Children from ListBox can't get children that haven't been viewed

I've got a listbox in WPF like the following XAML. It's full of ListBoxItems that have a checkbox and a label inside of them. One of my items at the top is a "select all" option. When I click the select all option, I have a handler that iterates through all listbox items and it's supposed to check all the checkboxes on all the other listbox children. The problem is that it's only doing the visible children and when it hits the non-visible listboxitems, the VisualTreeHelper seems to be returning null when looking for objects of a specific type (like CheckBox). It seems that VisualTreeHelper seems to be problematic here. Am I using it wrong? Any help appreciated. One other detail - if I scroll and view all listboxitems at least once, it works fine.

mj

XAML - A simple listbox with a ton of children (only the 1st child displayed for brevity)

    <ListBox Grid.Row="0" Margin="0,0,0,0" Name="CharacterListBox">
        <ListBoxItem>
            <StackPanel Orientation="Horizontal">
                <CheckBox HorizontalAlignment="Center" VerticalAlignment="Center" Click="AllCharactersClicked"></CheckBox>
                <Label Padding="5">All Characters</Label>
            </StackPanel>
        </ListBoxItem>

C# - Two functions, the first is a helper method which walks the object tree using VisualTreeHelper (I found this on some website). The second function is the click handler for the "select all" listboxitem. It iterates through all children and attempts to check all checkboxes.

    private T FindControlByType<T>(DependencyObject container, string name) where T : DependencyObject
    {
        T foundControl = null;

        //for each child object in the container
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(container); i++)
        {
            //is the object of the type we are looking for?
            if (VisualTreeHelper.GetChild(container, i) is T && (VisualTreeHelper.GetChild(container, i).GetValue(FrameworkElement.NameProperty).Equals(name) || name == null))
            {
                foundControl = (T)VisualTreeHelper.GetChild(container, i);
                break;
            }
            //if not, does it have children?
            else if (VisualTreeHelper.GetChildrenCount(VisualTreeHelper.GetChild(container, i)) > 0)
            {
                //recursively look at its children
                foundControl = FindControlByType<T>(VisualTreeHelper.GetChild(container, i), name);
                if (foundControl != null)
                    break;
            }
        }

        return foundControl;
    }

    private void AllCharactersClicked(object sender, RoutedEventArgs e)
    {

        MainWindow.Instance.BadChars.Clear();

        int count = 0;
        foreach (ListBoxItem item in CharacterListBox.Items)
        {
            CheckBox cb = FindControlByType<CheckBox>(item, null);                
            Label l = FindControlByType<Label>(item, null);
            if (cb != null && l != null)
            {
                count++;
                cb.IsChecked = true;

                if (cb.IsChecked == true)
                {
                    string sc = (string)l.Content;
                    if (sc.Length == 1)
                    {
                        char c = Char.Parse(sc);
                        MainWindow.Instance.BadChars.Add(c);
                    }
                }
            }

        }

    }

Upvotes: 0

Views: 1595

Answers (1)

brunnerh
brunnerh

Reputation: 184622

Those visual tree walking methods floating around all over the place are a plague. You should almost never need any of that.

Just bind the ItemsSource to a list of objects containing properties for the CheckBoxes, create a data template (ItemTemplate) and bind that property to the CheckBox. In code just iterate over the collection bound to ItemsSource and set the porperty.

Upvotes: 3

Related Questions