WPF Lover
WPF Lover

Reputation: 91

How to set header for tabitem, when items adding through xaml views in tabcontrol WPF?

I am adding 5 XAML views (i.e. UserControls) to the Tab Control WPF. The corresponding tab items for each UserControl has rendered as expected. But I wonder how to set header for those tab items. Is there any way? Note: I dont want to add tab items directly to a TabControl.

My UserControl:

public class TimeConsumingView : UserControl
{
    public string Header
    {
        get { return (string)GetValue(HeaderProperty); }
        set { SetValue(HeaderProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Header.
    // This enables animation, styling, binding, etc...
    public static readonly DependencyProperty HeaderProperty =
        DependencyProperty.Register(
            "Header",
            typeof(string),
            typeof(TimeConsumingView),
            new UIPropertyMetadata(
                "",
                new PropertyChangedCallback(OnHeaderChanged)));
}

My Shell view:

 <TabControl x:Name="TabControl">
     <TabControl.ItemTemplate>
         <DataTemplate>
             <TextBlock Text="{Binding Header}"  x:Name="grid" />
         </DataTemplate>
     </TabControl.ItemTemplate>
     <!--<local:GeneralView Header="General"/>-->
     <local:TimeConsumingView Header="2006 - 2007"/>
     <local:TimeConsumingView Header="2007 - 2008"/>
 </TabControl>

In this case, the header not bound to the TextBlock. When seen from Snoop, it seems the DataContext cannot traverse after the ContentPresenter of TabItem Header.

Upvotes: 1

Views: 2156

Answers (2)

Rachel
Rachel

Reputation: 132558

Why don't you want to wrap your items in a TabItem?

WPF does that anyways when it renders, which I suspect is your problem because the Header is null by default, so the ItemTemplate has a null DataContext (You can verify this with Snoop)

<TabControl x:Name="TabControl">
    <TabControl.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Header}"  x:Name="grid" />
        </DataTemplate>
    </TabControl.ItemTemplate>
    <!--<local:GeneralView Header="General"/>-->
    <TabItem Header="2006 - 2007">
        <local:TimeConsumingView Header="2006 - 2007"/>
    </TabItem>
    <TabItem Header="2007 - 2008">
        <local:TimeConsumingView Header="2007 - 2008"/>
    </TabItem>
</TabControl>

If you really insist on not using a TabItem wrapper (which WPF will insert by default), use a TabItem Style which will set the Header property

<Style TargetType="{x:Type TabItem}">
    <Setter Property="Header" Value="{Binding Header}" />
</Style>

Upvotes: 2

eandersson
eandersson

Reputation: 26352

I handle this by having a String in my ViewModel that contains the name of the Tabitem. I then simply bind to that String using XAML Bindings.

<TabControl
        ItemsSource="{Binding Workspaces}" 
        SelectedItem="{Binding CurrentPage, Mode=TwoWay}" 
        SelectedIndex="{Binding SelectedWorkspace, UpdateSourceTrigger=PropertyChanged}">
    <TabControl.ItemTemplate>
        <DataTemplate>
            <DockPanel>
                  <TextBlock Text="{Binding Header}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
            </DockPanel>
        </DataTemplate>
    </TabControl.ItemTemplate>
</TabControl>

Inside my ViewModel for the Tab I have a property called Header.

public String Header { get; set; }

public MyConstructor()
{
     Header = "Name of Tab";
}

An alternative solution would be to override ToString().

public override string ToString()
{
    return "Name of my Tab";
}

Upvotes: 1

Related Questions