【问题标题】:Get Children from ListBox can't get children that haven't been viewed从 ListBox 中获取子项无法获取未查看的子项
【发布时间】:2012-08-15 21:57:46
【问题描述】:

我在 WPF 中有一个类似于以下 XAML 的列表框。它充满了 ListBoxItems,里面有一个复选框和一个标签。我的顶部项目之一是“全选”选项。当我单击全选选项时,我有一个遍历所有列表框项目的处理程序,它应该检查所有其他列表框子项上的所有复选框。问题是它只处理可见的子项,当它遇到不可见的列表框项时,VisualTreeHelper 在查找特定类型的对象(如 CheckBox)时似乎返回 null。看来 VisualTreeHelper 似乎在这里有问题。我用错了吗?任何帮助表示赞赏。另一个细节 - 如果我滚动并查看所有列表框项至少一次,它工作正常。

mj

XAML - 一个包含大量子项的简单列表框(为简洁起见,仅显示第一个子项)

    <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# - 两个函数,第一个是一个辅助方法,它使用 VisualTreeHelper 遍历对象树(我在某个网站上找到了这个)。第二个函数是“全选”列表框项的单击处理程序。它遍历所有子项并尝试检查所有复选框。

    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);
                    }
                }
            }

        }

    }

【问题讨论】:

  • 您应该考虑使用绑定而不是遍历可视化树。
  • 快速了解您遇到的情况;列表框使用虚拟化堆栈面板 (sp),它仅在需要时分配可视控件(出于效率原因)。这意味着可能会或可能不会分配控件,从而使遍历可视化树以随意进行数据操作(这也不是可视化树的用途)。正如其他人提到的那样,绑定是要走的路。

标签: c# wpf xaml


【解决方案1】:

那些随处可见的视觉树行走方法是一种瘟疫。你应该几乎不需要这些。

只需将ItemsSource 绑定到包含CheckBoxes 属性的对象列表,创建data template (ItemTemplate) 和bind 将该属性绑定到CheckBox。在代码中,只需遍历绑定到 ItemsSource 的集合并设置属性。

【讨论】:

    猜你喜欢
    • 2023-03-24
    • 1970-01-01
    • 2012-05-18
    • 1970-01-01
    • 2020-11-22
    • 1970-01-01
    • 1970-01-01
    • 2012-03-04
    • 2015-05-27
    相关资源
    最近更新 更多