wpf VisualTreeHelper.GetChildren 找不到 TabItem 的子项

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12116339/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 05:05:51  来源:igfitidea点击:

VisualTreeHelper.GetChildren does not find children of TabItem

wpftabcontrolvisualtreehelper

提问by Klaus Nji

I have the following C# code to find children of a DepedendencyObject:

我有以下 C# 代码来查找 DepedendencyObject 的子项:

public static IEnumerable<T> FindVisualChildren<T>(DependencyObject parent) where T : DependencyObject
    {
        int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
        for (int i = 0; i < childrenCount; i++)
        {
            var child = VisualTreeHelper.GetChild(parent, i);

            T childType = child as T;
            if (childType == null)
            {
                foreach (var other in FindVisualChildren<T>(child))
                    yield return other;
            }
            else
            {
                yield return (T)child;
            }
        }
    }

When I loop through the TabItems in the XAML posted at the bottom, passing each TabItem to the above method, asking it to find all Expanders, it returns nothing. Also, I am making this request in an event handler attached to the Loaded event of each tab item.

当我遍历底部张贴的 XAML 中的 TabItem,将每个 TabItem 传递给上述方法,要求它查找所有扩展器时,它不返回任何内容。此外,我在附加到每个选项卡项的 Loaded 事件的事件处理程序中发出此请求。





                                <TextBlock Text="Number of Parts" Grid.Column="0"/>                                   
                                <ComboBox Grid.Column="2"                                              
                                          Margin="0,0,0,2"                                                                                                                                        
                                          />                                                              
                            </Grid>
                        </Expander>
                        <Expander Header="Date/Time Format" 
                  Margin="5,0,5,0"
                   Padding="3,3,0,0"
                  IsExpanded="True" >
                            <Grid Margin="20,4,0,4">
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="25"/>
                                    <RowDefinition Height="Auto"/>
                                </Grid.RowDefinitions>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition/>                                                                  
                                    <ColumnDefinition Width="*" />
                                </Grid.ColumnDefinitions>
                                <TextBlock Text="Date/Time Format" Grid.Row="0"/>
                                <ComboBox Name="cmbDateTimeFormats"                                             
                                          Grid.Row="0" Grid.Column="2"/>
                            </Grid>
                        </Expander>                           
                    </StackPanel>                       
                </DockPanel>
            </Border>                
        </TabItem>
        <TabItem Header="Profile">
            <Border  >
                <DockPanel LastChildFill="False">
                    <StackPanel DockPanel.Dock="Top">
                        <GroupBox Header="Local" 
                              Margin="5,8" Padding="3,3,0,0"
                              >                                 
                            <Grid Margin="20,4,0,4">
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="25"/>
                                    <RowDefinition Height="Auto"/>
                                    <RowDefinition Height="Auto"/>
                                    <RowDefinition Height="Auto"/>
                                </Grid.RowDefinitions>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition  />
                                    <ColumnDefinition  />
                                    <ColumnDefinition  />

                                    <ColumnDefinition Width="*" />
                                </Grid.ColumnDefinitions>

                                <Button Content="Location..." Grid.Row="0" Name="btnProfLoc"    />
                                <TextBlock Text="{Binding ProfileLocation}" Grid.Row="0" Grid.Column="2"/>

                                <Button Name="btnSaveProfile" Height="25"
                                        Margin="2,5,0,0" Grid.Row="1"                                           
                                        Padding="2,1" >                                    
                                    <StackPanel Orientation="Horizontal">                                       
                                        <TextBlock Text="Save" Margin="5,0"/>
                                    </StackPanel>
                                </Button>

                                <Button Name="btnLoadProfile" Height="25"
                                        Margin="2,5,0,0" Grid.Row="2"                                           
                                        Padding="2,1" >
                                    <StackPanel Orientation="Horizontal">

                                        <TextBlock Text="Load" Margin="5,0"/>
                                    </StackPanel>
                                </Button>

                                <Button Name="btnResetProfile" Height="25"
                                        Margin="2,5,0,0" Grid.Row="3"                                           
                                        Padding="2,1" >
                                    <StackPanel Orientation="Horizontal">                                         
                                        <TextBlock Text="Reset" Margin="5,0"/>
                                    </StackPanel>
                                </Button>                                    
                            </Grid>
                        </GroupBox>                       
                    </StackPanel>
                    <StackPanel 
                    DockPanel.Dock="Bottom" Orientation="Horizontal">

                    </StackPanel>
                </DockPanel>
            </Border>                
        </TabItem>
    </TabControl>

Any guesses what is wrong with my approach? I have not tried in this particular custom control but this method has been used to find children of a given type in another custom control. Main difference is that the items I am looking for are children of TabItems.

任何猜测我的方法有什么问题?我还没有在这个特定的自定义控件中尝试过,但是这个方法已被用于在另一个自定义控件中查找给定类型的子项。主要区别在于我要查找的项目是 TabItems 的子项。

回答by Nigel Thorne

The controls within a tab don't seem to be the children of a TabItem in the visual tree. They are the children of a TabControl.

选项卡中的控件似乎不是可视化树中 TabItem 的子项。它们是 TabControl 的子项。

You can see what I mean if you add the following code to your app.. and include a button on the tab with a click handler that reports the button's Path.

如果您将以下代码添加到您的应用程序中,您就会明白我的意思.. 并在选项卡上包含一个按钮,该按钮带有一个报告按钮路径的点击处理程序。

public string Id(object control)
{
    if (control is UIElement)
    {
        string id = ((UIElement)control).GetValue(AutomationProperties.AutomationIdProperty).ToString();
        id += "(" + control.GetType().Name + ")";
        return id;
    }
    return "not a ui element";
}

private static T FindParent<T>(DependencyObject child)
    where T : DependencyObject
{
    if (child == null) return null; 
    var parent = VisualTreeHelper.GetParent(child);
    return parent as T ?? FindParent<T>(parent);
}

public string Path(object control)
{
    if ( control == null ) return "";
    var path = Id(control);
    var parent = FindParent<FrameworkElement>(control as UIElement);
    if (parent != null ) path = Path(parent) +"/"+ path;
    return path;
}

For my application I get the following: "MainForm(MainPage)/(Grid)/(StackPanel)/TabControl(TabControl)/(Grid)/(Grid)/(Border)/(ContentPresenter)/(StackPanel)/Button(Button)"

对于我的应用程序,我得到以下内容:“MainForm(MainPage)/(Grid)/(StackPanel)/TabControl(TabControl)/(Grid)/(Grid)/(Border)/(ContentPresenter)/(StackPanel)/Button(Button )”

Notice the TabControl, but no TabItem.

注意 TabControl,但没有 TabItem。

If I hook up to events from the TabItem itself I get the following path: "MainForm(MainPage)/(Grid)/(StackPanel)/TabControl(TabControl)/(Grid)/(Grid)/(TabPanel)/MyTabItem(TabItem)"

如果我连接到 TabItem 本身的事件,我会得到以下路径:“MainForm(MainPage)/(Grid)/(StackPanel)/TabControl(TabControl)/(Grid)/(Grid)/(TabPanel)/MyTabItem(TabItem )”

This shows the items don't exist within the TabItem in the visual tree, but as children of the TabControl. (Which sucks.) Note: they are virtualized and realized as you change tabs.

这表明这些项目不存在于可视化树的 TabItem 中,而是作为 TabControl 的子项。(这很糟糕。)注意:它们在您更改选项卡时被虚拟化和实现。