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

Ale*_*all 3 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>
Run Code Online (Sandbox Code Playgroud)

代码背后:

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;
Run Code Online (Sandbox Code Playgroud)

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

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

ito*_*son 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;
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

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

<local:DeviceTypeSelector x:Key="dts"
                          PendantTemplate="{StaticResource pt}"
                          DefaultTemplate="{StaticResource dt}" />
Run Code Online (Sandbox Code Playgroud)

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

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

<TabControl Name="EditorTabs"
            ContentTemplateSelector="{StaticResource dts}" />
Run Code Online (Sandbox Code Playgroud)

并将其设置为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>
Run Code Online (Sandbox Code Playgroud)

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