Создание элементов вкладок с разным содержимым во время выполнения на основе шаблонов в WPF

Я пишу приложение с WPF, и часть его включает в себя управление для пользователя различными файлами, которые используются для настройки пользовательских внутренних устройств. Мне нужно иметь возможность манипулировать различными типами конфигураций на вкладках одного и того же элемента управления TabControl, что означает, что содержимое элементов вкладок должно создаваться динамически. Я хотел бы сделать это с помощью ControlTemplates, но мне пока не удалось получить рабочий шаблон. У меня есть ControlTemplate под названием «pendantConfigurationTabItemTemplate», определенный в моих ресурсах Window, и я использую следующий код, чтобы применить шаблон (который содержит именованный элемент, к которому мне нужно получить доступ) к 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.


person Alex Marshall    schedule 29.12.2009    source источник


Ответы (1)


TabControl.ItemsSource plus DataTemplates - это, по сути, то решение «шаблоны как фабрики», о котором вы просите, но оно требует немного другого подхода по сравнению с вашим текущим.

Вместо того, чтобы писать процедурный код для создания и шаблонов TabItems и вызова Items.Add, используйте свойство ItemsSource и привязку данных. Это заставит WPF создать TabItem для каждого объекта в ItemsSource. Затем вы можете использовать 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 - подходящие шаблоны данных, определенные в других местах ресурсов).

Наконец, ваш TabControl будет выглядеть так:

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

и вы установите его как EditorTabs.ItemsSource = myConfigFiles; (или, еще лучше, позвольте ему получить ItemsSource в XAML из DataContext).

Вы также захотите настроить заголовки TabItems: для этого используйте TabControl.ItemContainerStyle с Setter для свойства Header. Думаю, это будет выглядеть примерно так:

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

(Кстати, вы также можете встроить ContentTemplateSelector: я разбил его на ресурс в основном для того, чтобы показывать вещи меньшими кусками.)

person itowlson    schedule 29.12.2009
comment
Это отличный ответ, я попробую. Однако я думал, что DataTemplates больше предназначены для отображения данных, а ControlTemplates предназначены для использования в качестве повторно используемых элементов управления, чтобы уменьшить количество пользовательских элементов управления, которые необходимо создать? Мне нужно иметь возможность редактировать объекты, которые отображаются / привязаны к данным на вкладках - person Alex Marshall; 29.12.2009
comment
Не бойтесь, DataTemplates предназначены для отображения и редактирования данных. Они могут абсолютно содержать элементы пользовательского интерфейса, которые обновляют отображаемый объект - просто убедитесь, что привязка элемента в DataTemplate является двусторонней (это значение по умолчанию для текстовых полей, но не для всех элементов управления). ControlTemplates больше касаются изменения пользовательского интерфейса элементов управления при одновременном использовании их существующего поведения, например отображение Button как отдельного графического элемента без обычного хромирования кнопок или TabControl в виде карусели, ролодекса или (бумажной) записной книжки. - person itowlson; 29.12.2009
comment
Ваше предложение сработало, и довольно хорошо. Большое спасибо, я очень ценю это :) - person Alex Marshall; 29.12.2009