Есть ли способ перебирать шаблоны элементов ListBox?

У меня есть список, содержащий элементы, представленные одним текстовым полем.

Когда пользователь нажимает кнопку, я хочу перебрать все эти текстовые поля и проверить, не содержат ли их выражения привязки ошибок; Должно быть что-то вроде:

    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

Любое обсуждение будет действительно оценено. Спасибо.


person Shimmy Weitzhandler    schedule 29.03.2009    source источник
comment
Вы явно помещаете элементы в ListBox или используете ItemsSource? Я предполагаю, что вы используете ItemsSource, учитывая, что вы упоминаете шаблон.   -  person Josh G    schedule 06.04.2009
comment
ItemsSource конечно. Это не было бы вопросом, если бы это было статично; это динамично.   -  person Shimmy Weitzhandler    schedule 07.04.2009


Ответы (2)


Возможно, есть более простой способ сделать это, но вот один из вариантов, который будет работать:

1) Итерация по списку элементов.

Поскольку вы используете источник элементов, ListBox.Items будет ссылаться на элементы данных в ItemsSource.

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

2) Получите контейнеры для этих предметов.

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

3) Используйте VisualTreeHelper для поиска дочернего элемента TextBox визуального элемента-контейнера.

TextBox box = FindVisualChild<TextBox>(obj);

Используйте эту функцию для поиска визуального потомка правильного типа:

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) Наконец, проверьте привязку к TextBox.

Все вместе, примерно так:

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;
}
person Josh G    schedule 07.04.2009
comment
Извините, я плохо знаю VB. Я могу его прочитать, но я знал, что он, вероятно, не скомпилировался бы, если бы я попытался написать это на VB. - person Josh G; 07.04.2009
comment
Я перевел это Спасибо за ваш пост. - person Shimmy Weitzhandler; 12.04.2009
comment
Я получаю null от ItemContainerGenerator.ContainerFromIndex(i); есть предположения, почему? <ListBox Name="lstUsers" Grid.Column="0" ItemsSource="{Binding Users}" SelectedItem="{Binding SelectedUser}" Margin="2" Width="275" SelectionMode="Single" ItemContainerStyle="{DynamicResource ListBoxItemStyle}"> и var item = (UserDataModel)lstUsers.Items[i]; не равны нулю - person Maslow; 16.11.2015
comment
очевидно, если я подожду, пока окно загрузится, а не просто будет вызвано InitializeComponent(), я не получу null. - person Maslow; 16.11.2015

Перевод предыдущего поста на VB:

1)

For i As Integer = 0 To ListBox.Items.Count - 1 
    ' do work as follows below... 
Next

2)

Dim obj As DependencyObject = ListBox.ItemContainerGenerator.ContainerFromIndex(i)

3)

Dim box As TextBox = FindVisualChild(Of TextBox)(obj)
'************************
Public Shared Function FindVisualChild(Of ChildItem As DependencyObject)(ByVal obj As DependencyObject) As ChildItem
    ' Search immediate children 
    For i As Integer = 0 To VisualTreeHelper.GetChildrenCount(obj) - 1
        Dim child As DependencyObject = VisualTreeHelper.GetChild(obj, i)
        If TypeOf child Is ChildItem Then
            Return child
        Else
            Dim childOfChild As ChildItem = FindVisualChild(Of ChildItem)(child)
            If childOfChild IsNot Nothing Then Return childOfChild
        End If
    Next
    Return Nothing
End Function

4)

Private Function ValidateList(ByVal lb As ListBox) As Boolean 
For i As Integer = 0 To lb.Items.Count - 1 
    Dim obj As DependencyObject = lb.ItemContainerGenerator.ContainerFromIndex(i) 
    Dim box As TextBox = FindVisualChild(Of TextBox)(obj) 
    If Not TestBinding(box) Then 
        Return False 
    End If 
Next 
Return True 

Конечная функция

person Shimmy Weitzhandler    schedule 11.04.2009