Josh
Josh

Reputation: 557

Add a template full of controls to another WPF control

So I've been working on a project that allows me to add tabs to a tab control and within each new TabItem. I have a bunch of programmatically generated controls. Is there a way to create a template in XAML that I can simply add to the newly created TabItem?

For a simple example, say I have a WPF form with a TabPage:

<Window>
 <Grid>
  <TabControl></Tabcontrol>
 </Grid> 
</Window>

And I want to add 3 buttons in each of my TabPages.

<Window>
 <Grid>
  <TabControl>
   <TabItem>
    <Button/>
    <Button/>
    <Button/>
   </TabItem>
  </TabControl>
 </Grid> 
</Window>

I'd like to be able to edit this template of 3 buttons in a XAML editor (probably VS2012) and those changes would be reflected in the template that is added to each TabItem.

I've looked around and most of the WPF template articles are in regards to coloring or style templates which don't seem to be what I want. As per my current approach, adding TabItem programmatically works but makes editing the template a little more cumbersome and, what I believe, contrary to the philosophy of WPF: disconnecting code from design.

I'm rather new to WPF but already see the power and advantages to it over WinForms so I'm sold on that avenue but because I'm new, my terminology is sometimes a bit confusing, which also makes my attempts to search fail, from time to time.

Any help would be appreciated. If I didn't explain it well enough, let me know.

Upvotes: 2

Views: 360

Answers (4)

flq
flq

Reputation: 22829

TabItem ultimately inherits from ContentControl, which means that you can template it in a way where you can adorn the actual content displayed in the content control:

<Style TargetType="TabItem">
  <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="{x:Type TabItem}">
          <Grid>
            <Grid.RowDefinitions>
              <RowDefinition Height="*" />
              <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
            <ContentPresenter Grid.Row="0" />
            <StackPanel Grid.Row=1>
              <!-- Your buttons -->
            </StackPanel>
          </Grid>
        </ControlTemplate>
      </Setter.Value>
  </Setter>
</Style>

The place where you put the ContentPresenter is the place where the Content of the ContentControl (or in this case the TabItem) is placed.

We have used this for example to add search/highlight capabilities to collection displays. You may want to copy the default template and modify from there - This is the ugly part as it is rather difficult to practice markup reuse within a template.

Alternatively, you leave the TabItem as it is, and style a ContentControl in the desired fashion which you use inside the TabItems...

<TabItem>
  <ContentControl Style="{StaticResource CommonButtons}">
    <!-- TabItem Contents -->
  </ContentControl>
</TabItem>

Of course, the ContentControl bit can end up in a DataTemplate, and with binding to an ItemsSource you end up with

<TabControl 
   ItemTemplate="{StaticResource CommonButtonsTemplate}" 
   ItemsSource="{Binding MyTabItemsData}" />

Upvotes: 1

Maverik
Maverik

Reputation: 5671

As @Olwaro mentioned, you probably want to use a UserControl.

Given your example you can have a UserControl with this Xaml (where the user control is called ThreeButtonStack and resides in namespace WpfApplication2):

<UserControl x:Class="WpfApplication2.ThreeButtonStack"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <UserControl.Resources>
        <Style TargetType="Button">
            <Setter Property="Margin" Value="5" />
            <Setter Property="Width" Value="75" />
        </Style>
    </UserControl.Resources>
    <StackPanel Orientation="Horizontal">
        <Button Content="OK" />
        <Button Content="Cancel" />
        <Button Content="Retry" />
    </StackPanel>
</UserControl>

Then you can call it in your main application like this:

<Window x:Class="WpfApplication2.TabPageWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:wpfApplication2="clr-namespace:WpfApplication2"
        Title="TabPageWindow" Height="300" Width="300">
    <TabControl>
        <TabItem Header="Tab 1">
            <DockPanel>
                <wpfApplication2:ThreeButtonStack DockPanel.Dock="Bottom" HorizontalAlignment="Right"/>
                <TextBlock>Custom Content</TextBlock>
            </DockPanel>
        </TabItem>
        <TabItem Header="Tab 2">
            <DockPanel>
                <wpfApplication2:ThreeButtonStack DockPanel.Dock="Bottom" HorizontalAlignment="Right"/>
                <TextBox>Editing custom stuff</TextBox>
            </DockPanel>
        </TabItem>
    </TabControl>
</Window>

and result would be:

Screenshot

Upvotes: 1

Olwaro
Olwaro

Reputation: 381

You sould try to use a UserControl.

It will allow you to use -for example- a group of three buttons as a simple control. It is defined by a xaml file and changes to this xaml file will be reflected wherever your usercontrol was added.

Upvotes: 1

yo chauhan
yo chauhan

Reputation: 12295

I dont have idea about class TabPage , but to solve this kind of problem it would be better you create a class that inherits TabPage and work in it,and set common functionality in it,Instead of using Templateing.I hope this will help.

Upvotes: 0

Related Questions