3

我正在使用 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 工厂

4

1 回答 1

5

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

与其编写程序代码来创建和模板化 TabItems 并调用 Items.Add,不如使用 ItemsSource 属性和数据绑定。这将导致 WPF 为 ItemsSource 中的每个对象创建一个 TabItem。然后,您可以使用 ContentTemplateSelector 为显示在此选项卡上的对象选择适当的模板,根据任何适当的标准(例如 Device 属性)——尽管在这种情况下您将使用 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:我将其分解为一个资源,主要是为了以较小的块显示内容。)

于 2009-12-29T01:21:06.907 回答