11

The following example xaml causes each tab item to share the same TextBox. It makes sense, on some level I guess... but it's unexpected behavior, and almost feels like a bug. And I couldn't find any information in the docs explaining the behavior, or how to correctly get around it.

<TabControl>
    <TabControl.Resources>
        <Style TargetType="TabItem">
            <Setter Property="ContentTemplate">
                <Setter.Value>
                    <DataTemplate>
                        <TextBox />
                    </DataTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </TabControl.Resources>
    <TabItem Name="tab1" />
    <TabItem Name="tab2" />
</TabControl>

When switching between tab1 and tab2, the same TextBox is used, when I would expect a new TextBox for each tab. How can I get the latter case?

Subclassing TabItem and making its content a TextBox by default is one way to do it, but I just want to be sure there isn't something I'm missing.

Edit

I realize that setting the content explicitly for each tab will solve the problem, but the tabs are to be created dynamically. I want to use the content template so that I may add new tabs via data binding and have the content unshared as it is causing quirky behavior.

Perhaps with the current implementation of the TabControl, there is no declarative approach to solving this. It's pretty trivial setting the content in code, but such things always feel wrong in WPF. To me, this seems like an unjustified optimization of the TabControl; it should at least be optional for situations where it is not practical.

gotopie
  • 2,594
  • 1
  • 20
  • 23
  • What is your goal? I'm sure we can find a solution to your problem in a different way, once we know that =) – hkon Aug 15 '10 at 01:45
  • 2
    I don't have a good solution for that issue, but I'm really interested in the answers that might come up... This behavior is a real pain. Sometimes it makes sense that the content template is shared between tabs, but very often it doesn't, typically when you're making a tabbed document interface – Thomas Levesque Aug 15 '10 at 02:06
  • @hkon: I want each tab to have its own content as defined in the template instead of sharing a single instance between tabs. Data binding works at keeping bound data in sync between tabs, but this can cause some issues. Maybe the user adjusted a scroll bar in one tab, and its position is then forgotten after switching back to it. – gotopie Aug 15 '10 at 03:19

3 Answers3

5

I suspect there's a nicer way to achieve whatever it is you're trying to achieve, but I think this will work (would test but I'm on linux atm):

<TabControl>
    <TabControl.Resources>
        <Style TargetType="TabItem" x:Shared="False">
            <Setter Property="ContentTemplate">
                <Setter.Value>
                    <DataTemplate>
                        <TextBox />
                    </DataTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </TabControl.Resources>
    <TabItem Name="tab1" />
    <TabItem Name="tab2" />
</TabControl>
Kent Boogaart
  • 175,602
  • 35
  • 392
  • 393
  • 2
    Ah, this looked promising... unfortunately, each time a tab is selected, its old content is overwritten with a new empty TextBox. – gotopie Aug 16 '10 at 02:28
0

I had the same problem, and found this post explaining why this happens and how to workaround it. This is the link, just in case someone else come around with the same issue:

http://www.codeproject.com/Articles/460989/WPF-TabControl-Turning-Off-Tab-Virtualization

Alejandro Martin
  • 5,691
  • 1
  • 17
  • 21
0

It will work if you define a usercontrol that has the tab content in it. I created the following usercontrol:

<UserControl x:Class="SO_Testing.TextBoxUC"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <TextBox/>
    </Grid>
</UserControl>

Then I modified my window xaml to be this:

<Window x:Class="SO_Testing.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:SO_Testing"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TabControl>
            <TabItem Name="tab1" Header="Test">
                <local:TextBoxUC/>
            </TabItem>
            <TabItem Name="tab2" Header="Test 2">
                <local:TextBoxUC/>
            </TabItem>
        </TabControl>
    </Grid>
</Window>

This may not be exactly what you are wanting, but at least the layout of each tab is only defined in one place and you can then assign a datacontext to each usercontrol to show the values for each of your tabs.

aalex675
  • 421
  • 1
  • 7
  • 15
  • This doesn't solve the problem I was illustrating. The UserControl here is also pointless, because if you specifically set the content as you did here it will work with a plain old TextBox; the problem is with the content template causing content to be shared among tabs whose content is not set explicitly. I did, however, try to use a UserControl in the template to see if it would make any difference but, as expected, it didn't. I updated my question to be more clear. – gotopie Aug 17 '10 at 03:02