C# 具有绑定TabItems的TabControl的逻辑子级

C# 具有绑定TabItems的TabControl的逻辑子级,c#,.net,wpf,xaml,tabcontrol,C#,.net,Wpf,Xaml,Tabcontrol,我有一个选项卡控件,它的项资源绑定到一个可观察集合。在这种情况下,TabControl没有逻辑子级(logicaltreeheloper.GetChildren(tabctrl)返回空列表) 如果我将TabItem手动添加到TabControl.Items集合,则TabItem是TabControl的逻辑子级 为什么这些方式表现不同?在这两种情况下,TabControl不应该都有一个逻辑子级吗 示例代码: XAML <Window x:Class="WpfApplication29.Mai

我有一个
选项卡控件
,它的
项资源
绑定到一个
可观察集合
。在这种情况下,
TabControl
没有逻辑子级(
logicaltreeheloper.GetChildren(tabctrl)
返回空列表)

如果我将
TabItem
手动添加到
TabControl.Items
集合,则
TabItem
是TabControl的逻辑子级

为什么这些方式表现不同?在这两种情况下,
TabControl
不应该都有一个逻辑子级吗

示例代码:

XAML

<Window x:Class="WpfApplication29.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
  <StackPanel>
    <TabControl Name="tabctrl"/>
    <Button Content="count children" Click="Button_Click_2"/>
  </StackPanel>
</Window>

代码隐藏

using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;

namespace WpfApplication29
{
  public partial class MainWindow : Window
  {
    public ObservableCollection<string> TabItems
    {
      get { return (ObservableCollection<string>)GetValue(TabItemsProperty); }
      set { SetValue(TabItemsProperty, value); }
    }

    public static readonly DependencyProperty TabItemsProperty =
        DependencyProperty.Register("TabItems", typeof(ObservableCollection<string>), typeof(MainWindow), new PropertyMetadata(null));

    public MainWindow()
    {
      InitializeComponent();

      TabItems = new ObservableCollection<string>();
      TabItems.Add("foo");

      //scenario 1 (Visual Children count: 1, logical children count: 0)
      tabctrl.SetBinding(TabControl.ItemsSourceProperty, new Binding("TabItems") { Source = this });

      //scenario 2 (Visual Children count: 1, logical children count: 1)
      //tabctrl.Items.Add(new TabItem() { Header = "bar", Content = "bar" });

    }
    private void Button_Click_2(object sender, RoutedEventArgs e)
    {
      var visualChildrenCount = VisualTreeHelper.GetChildrenCount(tabctrl);
      var logicalChildrenCount = LogicalTreeHelper.GetChildren(tabctrl).Cast<object>().Count();

      MessageBox.Show(string.Format("Visual Children: {0}, Logical Children: {1}", visualChildrenCount, logicalChildrenCount));
    }
  }
}
使用System.Collections.ObjectModel;
使用System.Linq;
使用System.Windows;
使用System.Windows.Controls;
使用System.Windows.Data;
使用System.Windows.Media;
命名空间WpfApplication29
{
公共部分类主窗口:窗口
{
公共可观测集合选项卡项
{
get{return(ObservableCollection)GetValue(TabItemsProperty);}
set{SetValue(TabItemsProperty,value);}
}
公共静态只读从属属性选项卡ItemsProperty=
DependencyProperty.Register(“TabItems”、typeof(ObservableCollection)、typeof(MainWindow)、new PropertyMetadata(null));
公共主窗口()
{
初始化组件();
TabItems=新的ObservableCollection();
TabItems.添加(“foo”);
//场景1(可视子项计数:1,逻辑子项计数:0)
tabctrl.SetBinding(TabControl.ItemsSourceProperty,新绑定(“TabItems”){Source=this});
//场景2(可视子项计数:1,逻辑子项计数:1)
//tabctrl.Items.Add(新的TabItem(){Header=“bar”,Content=“bar”});
}
私有无效按钮\u单击\u 2(对象发送方,路由目标)
{
var visualChildrenCount=visualtreeheloper.GetChildrenCount(tabctrl);
var logicalChildrenCount=LogicalTreeHelper.GetChildren(tabctrl.Cast().Count();
Show(string.Format(“可视子项:{0},逻辑子项:{1}”,visualChildrenCount,logicalChildrenCount));
}
}
}

如果将控件添加到用户控件或页面,则该控件将添加到其逻辑树中。但是,控件模板中的UIElements不是LogicalTree的一部分

总之,当您将TabItem直接添加到TabControl时,您希望直观地显示在LogicalTree中。你直接加在那里了

但是,当从itemssource生成项时,TabItems由控件的内部逻辑生成,并且不会添加到LogicalTree

也许更好的例子是ListBox或DataGrid。假设您将ItemsSource绑定到非常大的集合,并且需要启用虚拟化。然后只在需要时生成项目(UIElements)(它们位于scrollviewver的可见区域)。如果它们位于逻辑树中,则在滚动时逻辑树会发生变化。但滚动更多的是视觉效果,而不是“UI逻辑”

本文有助于更好地理解逻辑树: