根据WPF中的模板在运行时创建具有不同内容的TabItem [英] Create TabItems with differing content at runtime based on templates in WPF

查看:113
本文介绍了根据WPF中的模板在运行时创建具有不同内容的TabItem的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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>

后面的代码:

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 ?

有效地,我想做的是将WPF模板用作TabItem工厂

Effectively, what I want to do is use the WPF templates as TabItem factories

推荐答案

TabControl.ItemsSource 加上DataTemplates实际上是您所要求的模板作为工厂"解决方案,但它需要一种略有不同的方法到您当前的那一个.

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.

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

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:

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中实例化如下:

and will be instantiated in XAML like this:

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

(其中pt和dt是在资源中其他位置定义的合适的DataTemplates).

(where pt and dt are suitable DataTemplates defined elsewhere in the resources).

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

Finally, your TabControl will look like this:

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

,然后将其设置为 EditorTabs.ItemsSource = myConfigFiles; (或者最好还是让它从DataContext中获取XAML中的ItemsSource).

and you set it up as EditorTabs.ItemsSource = myConfigFiles; (or better still let it acquire the ItemsSource in XAML from the DataContext).

您还需要设置TabItems的标题:为此,请使用TabControl.ItemContainerStyle,并将Header属性设置为Setter.我认为这看起来像这样:

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:

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

(顺便说一下,您也可以内联ContentTemplateSelector:我主要将其拆分为资源,以便以较小的块显示内容.)

(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.)

这篇关于根据WPF中的模板在运行时创建具有不同内容的TabItem的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆