VisualTreeHelper.GetChildrenCount返回0?

16
我正在使用VisualTreeHelper.GetChildrenCount()来查找子控件,但它总是返回0。
这是我的代码:
<ScrollViewer x:Name="scrollViewerChannelsRecordTimeData">
    <StackPanel x:Name="channelsRecordTimeData">
        <ItemsControl x:Name="channelRecordTimeItems" ItemsSource="{Binding}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Grid x:Name="hoursLines">
                        //Some Controls here                            
                    </Grid>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </StackPanel>
</ScrollViewer>   

C# 代码:

channelRecordTimeItems.ItemContainerGenerator.StatusChanged += ChannelRecordTimeItemsStatusChangedEventHandler;
private void ChannelRecordTimeItemsStatusChangedEventHandler(Object sender, EventArgs e)
{
    if (channelRecordTimeItems.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
    {
        if (channelRecordTimeItems.HasItems)
        {
            DependencyObject dependencyObject = null;
            Grid gridHighlightRecordData = null;
            for (int i = 0; i < channelRecordTimeItems.Items.Count; i++)
            {
                dependencyObject = channelRecordTimeItems.ItemContainerGenerator.ContainerFromIndex(i); //dependencyObject != null
                 if (dependencyObject != null)
                 {
                    Grid hoursLines = FindElement.FindChild<Grid>(dependencyObject, "hoursLines"); //hoursLines = null
                 }
            }
        }
    }
}

public static T FindChild<T>(DependencyObject parent, string childName)
   where T : DependencyObject
{
    // Confirm parent and childName are valid. 
    if (parent == null) return null;

    T foundChild = null;

    int childrenCount = VisualTreeHelper.GetChildrenCount(parent); //Return 0 here
    for (int i = 0; i < childrenCount; i++)
    {
        var child = VisualTreeHelper.GetChild(parent, i);
        // If the child is not of the request child type child
        T childType = child as T;
        if (childType == null)
        {
            // recursively drill down the tree
            foundChild = FindChild<T>(child, childName);

            // If the child is found, break so we do not overwrite the found child. 
            if (foundChild != null) break;
        }
        else if (!string.IsNullOrEmpty(childName))
        {
            var frameworkElement = child as FrameworkElement;
            // If the child's name is set for search
            if (frameworkElement != null && frameworkElement.Name == childName)
            {
                // if the child's name is of the request name
                foundChild = (T)child;
                break;
            }
        }
        else
        {
            // child element found.
            foundChild = (T)child;
            break;
        }
    }

    return foundChild;
}

VisualTreeHelper.GetChildrenCount()总是返回0,

这里的代码用于构建项目。

List<ChannelRecordTimeItemData> listChannelRecordTimeItemData = new List<ChannelRecordTimeItemData>();
for(int i = 0; i < 5; i++)
{
    ChannelRecordTimeItemData item = new ChannelRecordTimeItemData();
    listChannelRecordTimeItemData.Add(ChannelRecordTimeItemData);
}
channelRecordTimeItems.ItemsSource = listChannelRecordTimeItemData;
channelRecordTimeItems.Items.Refresh();

我在论坛和互联网上搜索了很久,但是仍然无法解决问题,有人可以帮帮我吗?

非常感谢!

T&T


1
你能解释一下这个绑定吗,ItemsSource="{Binding}"?我认为你应该在这里绑定你的集合属性。 - Nitesh
谢谢,我已经添加了用于构建上述项目的代码。 - TTGroup
你是否在XAML和代码后台中绑定ItemsControl两次? - Nitesh
在将ItemsSource绑定到ItemsControl之后,您必须调用它。 - Nitesh
我进行了调试,发现在 channelRecordTimeItems.ItemsSource = listChannelRecordTimeItemData; 和 channelRecordTimeItems.Items.Refresh(); 之后调用了 Find() 函数。这样是正确的吗?谢谢! - TTGroup
显示剩余2条评论
2个回答

29

问题在于当ItemContainerGenerator发出ContainersGenerated状态信号时,容器(一个ContentPresenter)已经被创建,但尚未加载。特别地,数据模板还没有应用到ContentPresenter,因此可视树中没有任何内容。

在循环生成的容器上添加Loaded事件处理程序可以解决这个问题。

private void ItemContainerGeneratorStatusChanged(object sender, EventArgs e)
{
    if (itemsControl.ItemContainerGenerator.Status
        == GeneratorStatus.ContainersGenerated)
    {
        var containers = itemsControl.Items.Cast<object>().Select(
            item => (FrameworkElement)itemsControl
                .ItemContainerGenerator.ContainerFromItem(item));

        foreach (var container in containers)
        {
            container.Loaded += ItemContainerLoaded;
        }
    }
}

private void ItemContainerLoaded(object sender, RoutedEventArgs e)
{
    var element = (FrameworkElement)sender;
    element.Loaded -= ItemContainerLoaded;

    var grid = VisualTreeHelper.GetChild(element, 0) as Grid;
    ...
}

-1
如果您正在使用Caliburn.Micro,这将对您有所帮助。 对于您的Viewmodel,基类应该是Screen,然后只有VisualTreeHelper.GetChildrenCount()才会给出子元素数量。(因为Screen将激活所有子元素)
或者 否则(FrameworkElement)YourParent)。ApplyTemplate()方法

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接