带有两个数据绑定的 TabControl

问题描述

我有一个 TabControl,我想拥有 2 个数据绑定。一个是为列表中的每个项目设置一个 TabItem,另一个一个 Summary 并使用一个 TabItem显示控件模板另一个列表中的每个项目。

我可以将 ItemsControl 设置为这两种类型的数据绑定之一,但不能同时设置这两种类型的数据绑定。我怎样才能让 TabControl 做到这两点? 我可以以某种方式在 TabControl添加一个额外的 TabItemTabControl,ItemSource 集吗?然后我可以使用 XAML 加载新的额外 Binding

解决方法

公开组合集合

您可以在您的视图模型中公开一个集合,该集合将集合和附加项组合在一起,如下所示(如果您不修改该集合,您也可以使用任何其他可枚举类型)。

public class MyViewModel : INotifyPropertyChanged
{
   public MyViewModel()
   {
      var myTabItemCollection = // ...get the items collection.
      var mySummaryTabItem = // ...get the summary item.

      TabItems = new ObservableCollection<string>(myTabItemCollection)
      {
         mySummaryTabItem
      };
   }

   public ObservableCollection<MyTabItemViewModel> TabItems { get; }

   // ...other properties,methods,...
}

使用复合集合

有一种专用的 CompositeCollection 类型用于在 XAML 中组合一个或多个集合和单个项目。但是,这种类型具有 severe shortcommings in terms of data-binding。它既不是派生自 FrameworkElement,也不是 Freezable,这使得使用起来非常困难、繁琐且容易出错。为完整起见,我将介绍这种类型的解决方案。让我们假设这个视图模型:

public class MyViewModel : INotifyPropertyChanged
{
   public ObservableCollection<MyTabItemViewModel> TabItems { get; }

   public MyTabItemViewModel Summary { get; }

   // ...other properties,...
}

理论上,如果 CompositeCollection 可以进行数据绑定(这不起作用),这将很容易:

<TabControl>
   <TabControl.ItemsSource>
      <CompositeCollection>
         <CollectionContainer Collection="{Binding TabItems}" />
         <TabItem DataContext="{Binding Summary}"
                  Header="{Binding}"
                  Content="{Binding}" />
      </CompositeCollection>
   </TabControl.ItemsSource>
</TabControl>

为了使其发挥作用,您可以应用各种方法,例如在这些相关问题中:

例如,我将使用 binding proxy 类型来启用 CompositeCollection 内的绑定。它将绑定到 DataContextTabControl 并使用 Data 属性公开它。由于代理是一种资源,CompositeCollection 可以将其称为与 StaticResource 绑定的源。

<TabControl x:Name="TabControl">
   <TabControl.Resources>
      <local:BindingProxy x:Key="TabControlBindingProxy" Data="{Binding}" />
   </TabControl.Resources>
   <TabControl.ItemsSource>
      <CompositeCollection>
         <CollectionContainer Collection="{Binding Data.TabItems,Source={StaticResource TabControlBindingProxy}}" />
         <TabItem DataContext="{Binding Data.Summary,Source={StaticResource TabControlBindingProxy}}"
                  Header="{Binding}"
                  Content="{Binding}" />
      </CompositeCollection>
   </TabControl.ItemsSource>
</TabControl>

这也适用于多个集合和单个项目,但请注意,此方法和相关问题中的其他方法 - 尽管它们编译和运行得很好 - 可能会使 Visual Studio 设计器崩溃,这是不幸的。因此,我建议您采用公开组合集合的方式,这种方式更可靠、更容易理解、更简单。