I'm writing an application with WPF and part of it involves managing for the user various files which are used configure custom, in-house devices. I need to be able to manipulate different types of configurations in tabs in the same TabControl, meaning that the content of the TabItems must be dynamically generated. I'd like to do this with ControlTemplates, but I haven't been successful in getting a working template yet. I have a ControlTemplate called "pendantConfigurationTabItemTemplate" defined in my Window resources, and I use the following code to apply the template (which contains a named item I need to access) to the TabItems and add them to their parent 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>
Code behind :
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;
However, whenever I run the program, no tabs get added to the tab control, instead the tab control (seemingly) gets replaced or covered by the content of the template. Can somebody please help me out with this ?
Effectively, what I want to do is use the WPF templates as TabItem factories
Best Answer
TabControl.ItemsSource
plus DataTemplates is effectively the "templates as factories" solution you are asking for, but it demands a slightly different approach to your current one.Rather than writing procedural code to create and template TabItems and calling Items.Add, use the ItemsSource property and data binding. This will cause WPF to create a TabItem for each object in the ItemsSource. You can then use ContentTemplateSelector to select appropriate templates for the object displayed on this tab, according to whatever criteria are appropriate (e.g. the Device property) -- though in this case you will be using DataTemplates rather than ControlTemplates.
Your selector will look something like this:
and will be instantiated in XAML like this:
(where pt and dt are suitable DataTemplates defined elsewhere in the resources).
Finally, your TabControl will look like this:
and you set it up as
EditorTabs.ItemsSource = myConfigFiles;
(or better still let it acquire the ItemsSource in XAML from the DataContext).You'll also want to set up the headers of the TabItems: to do this, use TabControl.ItemContainerStyle, with a Setter for the Header property. I think this would look something like this:
(You can also inline the ContentTemplateSelector, by the way: I broke it out into a resource mostly so as to show things in smaller chunks.)