Search code examples
wpfdata-bindinglistboxlistboxitemlistboxitems

Is there a way to iterate in a ListBox Items templates?


I have a list box that contains items that are represented by a single textbox.

When the user clicks a button, I want to iterate thru all these text boxes and check if their binding expressions are clean of errors; Should be something like:

    Dim errCount = 0
    For Each item In MyListBox.ListBoxItems 'There is no such thing ListBoxItems which is actually what I am looking for.
        Dim tb As TextBox = item '.........Dig in item to extract the textbox from the visual tree.
        errCount += tb.GetBindingExpression(TextBox.TextProperty).HasError
    Next
    If errCount Then
        'Errors found!
    End If

Any discussion would be really appreciated. Thanks.


Solution

  • There may be an easier way to do this, but here is one option that will work:

    1) Iterate through the list of items.

    Because you are using items source, ListBox.Items will refer to the data items in the ItemsSource.

    for (int i = 0; i < ListBox.Items.Count; i++)
    {
        // do work as follows below...
    }
    

    2) Get the containers for these items.

    DependencyObject obj = ListBox.ItemContainerGenerator.ContainerFromIndex(i);
    

    3) Use VisualTreeHelper to search for a TextBox child of the container visual.

    TextBox box = FindVisualChild<TextBox>(obj);
    

    Use this function to search for a visual child of the correct type:

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

    4) Finally, examine the binding on the TextBox.

    All put together, something like this:

    private bool ValidateList(ListBox lb)
    {
        for (int i = 0; i < lb.Items.Count; i++)
        {
            DependencyObject obj = lb.ItemContainerGenerator.ContainerFromIndex(i);
            TextBox box = FindVisualChild<TextBox>(obj);
            if (!TestBinding(box))
                return false;
        }
    
        return true;
    }