根据WPF中的模板在运行时创建具有不同内容的TabItem

时间:2009-12-29 00:36:58

标签: wpf tabcontrol controltemplate tabitem

我正在使用WPF编写应用程序,其中一部分涉及为用户管理用于配置自定义内部设备的各种文件。我需要能够在同一个TabControl中的选项卡中操作不同类型的配置,这意味着必须动态生成TabItems的内容。我想用ControlTemplates做到这一点,但我还没有成功获得一个工作模板。我在我的Window资源中定义了一个名为“pendantConfigurationTabItemTemplate”的ControlTemplate,我使用以下代码将模板(包含我需要访问的命名项)应用到TabItems并将它们添加到它们的父TabControl中:

<ControlTemplate x:Key="pendantConfigurationTabItemTemplate" TargetType="TabItem">
    <StackPanel Orientation="Vertical">
        <my:PendantConfigurationFileEditor x:Name="configurationEditor"/>
        <StackPanel Style="{StaticResource defaultOkCancelButtonsContainerStyle}">
            <Button Style="{StaticResource defaultOkCancelButtonStyle}"/>
            <Button Style="{StaticResource defaultOkCancelButtonStyle}" Click="OkButton_Click"/>
        </StackPanel>
    </StackPanel>
</ControlTemplate>

代码背后:

TabItem ConfigTab = new TabItem();

switch (ConfigFile.Device)
{
  case DeviceType.PENDANT:
{
  ControlTemplate TabTemplate = Resources["pendantConfigurationTabItemTemplate"] as ControlTemplate;

  ConfigTab.Template = TabTemplate;
  ConfigTab.ApplyTemplate();

  object Editor = TabTemplate.FindName("configurationEditor", ConfigTab);

  PendantConfigurationFileEditor ConfigFileEditor = Editor as PendantConfigurationFileEditor;

  ConfigFileEditor.PendantConfiguration = DeviceConfig;

  break;
}
default:
  /* snipped */
  return;
}

ConfigTab.Header = ConfigFile.ConfigurationName;

this.EditorTabs.Items.Add(ConfigTab);
this.EditorTabs.SelectedIndex = this.EditorTabs.Items.Count - 1;

但是,每当我运行程序时,没有选项卡添加到选项卡控件,而是选项卡控件(看似)被模板内容替换或覆盖。有人可以帮我解决这个问题吗?

实际上,我想要做的是将WPF模板用作TabItem工厂

1 个答案:

答案 0 :(得分:5)

TabControl.ItemsSource加上DataTemplates实际上是您要求的“模板作为工厂”解决方案,但它需要与您当前的方法略有不同。

不是编写过程代码来创建和模板TabItems并调用Items.Add,而是使用ItemsSource属性和数据绑定。这将导致WPF为ItemsSource中的每个对象创建一个TabItem。然后,您可以根据适当的标准(例如,设备属性)使用ContentTemplateSelector为此选项卡上显示的对象选择适当的模板 - 但在这种情况下,您将使用DataTemplates而不是ControlTemplates。

你的选择器看起来像这样:

public class DeviceTypeSelector : DataTemplateSelector
{
  public DataTemplate PendantTemplate { get; set; }
  public DataTemplate DefaultTemplate { get; set; }

  public override SelectTemplate(object item, DependencyObject container)
  {
    ConfigFile cf = (ConfigFile)item;
    switch (cf.Device)
    {
      case DeviceType.Pendant: return PendantTemplate;
      default: return DefaultTemplate;
    }
  }
}

并将在XAML中实例化,如下所示:

<local:DeviceTypeSelector x:Key="dts"
                          PendantTemplate="{StaticResource pt}"
                          DefaultTemplate="{StaticResource dt}" />

(其中pt和dt是资源中其他地方定义的合适的DataTemplates。)

最后,您的TabControl将如下所示:

<TabControl Name="EditorTabs"
            ContentTemplateSelector="{StaticResource dts}" />

并将其设置为EditorTabs.ItemsSource = myConfigFiles;(或者更好的是让它从DataContext中获取XAML中的ItemsSource)。

您还需要设置TabItems的标头:要执行此操作,请使用TabControl.ItemContainerStyle,以及Header属性的Setter。我认为这看起来像这样:

<TabControl ...>
  <TabControl.ItemContainerStyle>
    <Style TargetType="TabItem">
      <Setter Property="Header" Value="{Binding ConfigurationName}" />
    </Style>
  </TabControl.ItemContainerStyle>
</TabControl>

(顺便说一下,你也可以内联ContentTemplateSelector:我把它分解成一个资源,主要是用较小的块来显示东西。)

相关问题