具有绑定 TabItems 的 TabControl 的逻辑 Children
Logical Children of TabControl with bound TabItems
我有一个 TabControl
,它的 ItemsSource
绑定到一个 ObservableCollection<string>
。在这种情况下,TabControl
没有逻辑 children(LogicalTreeHelper.GetChildren(tabctrl)
returns 一个空列表)。
如果我手动将 TabItem
添加到 TabControl.Items
集合,TabItem
是 TabControl 的逻辑 child。
为什么这些方式表现不同?在这两种情况下,TabControl
不应该有一个合乎逻辑的 child 吗?
示例代码:
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));
}
}
}
如果您将控件添加到您的用户控件或页面,它会添加到其 LogicalTree。但是,控件模板中的 UIElement 不是 LogicalTree 的一部分。
恕我直言,当您将 TabItem 直接添加到 TabControl 时,您希望直观地出现在 LogicalTree 中。您已直接将其添加到此处。
但是当项目是从itemssource 生成时,TabItems 是由控件的内部逻辑生成的,不会添加到LogicalTree。
也许更好的例子是 ListBox 或 DataGrid。想象一下,您将 ItemsSource 绑定到非常大的集合,并且您需要启用虚拟化。然后仅在需要时生成项目(UIElements)(它们在 scrollviewver 的可见区域中)。如果它们在逻辑树中,则逻辑树将在滚动时发生变化。但是滚动比 "UI logic".
更多的是关于视觉的
这篇文章有助于更好地理解逻辑树:http://www.codeproject.com/Articles/21495/Understanding-the-Visual-Tree-and-Logical-Tree-in
我有一个 TabControl
,它的 ItemsSource
绑定到一个 ObservableCollection<string>
。在这种情况下,TabControl
没有逻辑 children(LogicalTreeHelper.GetChildren(tabctrl)
returns 一个空列表)。
如果我手动将 TabItem
添加到 TabControl.Items
集合,TabItem
是 TabControl 的逻辑 child。
为什么这些方式表现不同?在这两种情况下,TabControl
不应该有一个合乎逻辑的 child 吗?
示例代码:
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));
}
}
}
如果您将控件添加到您的用户控件或页面,它会添加到其 LogicalTree。但是,控件模板中的 UIElement 不是 LogicalTree 的一部分。
恕我直言,当您将 TabItem 直接添加到 TabControl 时,您希望直观地出现在 LogicalTree 中。您已直接将其添加到此处。
但是当项目是从itemssource 生成时,TabItems 是由控件的内部逻辑生成的,不会添加到LogicalTree。
也许更好的例子是 ListBox 或 DataGrid。想象一下,您将 ItemsSource 绑定到非常大的集合,并且您需要启用虚拟化。然后仅在需要时生成项目(UIElements)(它们在 scrollviewver 的可见区域中)。如果它们在逻辑树中,则逻辑树将在滚动时发生变化。但是滚动比 "UI logic".
更多的是关于视觉的这篇文章有助于更好地理解逻辑树:http://www.codeproject.com/Articles/21495/Understanding-the-Visual-Tree-and-Logical-Tree-in