2

I have a TabControl that is data bound to an ObservableCollection like following

<TabControl  HorizontalAlignment="Stretch" 
        VerticalAlignment="Stretch" 
        Style="{DynamicResource BreadCrumbTabControl}" 
        ItemsSource="{Binding SalesItem.DispayedCategory}" 
        SelectedIndex="{Binding SalesItem.TabIndex}">

    <TabControl.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding DisplayText}" />
        </DataTemplate>
    </TabControl.ItemTemplate>
    <TabControl.ContentTemplate>
        <DataTemplate>
            <-- user control -->
        </DataTemplate>
    </TabControl.ContentTemplate>

</TabControl>

I wanted to style the tabs so the very first tab will have a different style and other tabs will have another style. I know how to do it if is not data bound.

<TabItem Header="Page 1" Style="{DynamicResource FirstTabItem}" />
<TabItem Header="Page 2" Style="{DynamicResource NormalTabItem}"/>

Can anyone help me out so I can achieve the above while the tabs are data bound?

Cheers.

daniele3004
  • 13,072
  • 12
  • 67
  • 75
Much Overflow
  • 3,142
  • 1
  • 23
  • 40

2 Answers2

2

I used ItemContainerStyleSelector

    <Window.Resources>
    <Style x:Key="first" TargetType="TabItem">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="TabItem">
                    <Border Background="CadetBlue" Height="50" Width="50">
                        <TextBlock Text="{Binding}"/>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <Style x:Key="others" TargetType="TabItem">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="TabItem">
                    <Border Background="Red" Height="50" Width="50">
                        <TextBlock Text="{Binding}"/>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <local:StyleSelector x:Key="StyleSelector" FirstStyle="{StaticResource first}" OtherStyles="{StaticResource others}"/>
 </Window.Resources>
    <TabControl ItemsSource="{Binding Lista}" ItemContainerStyleSelector="{StaticResource StyleSelector}"/>

and StyleSelector looks following

public class StyleSelector : System.Windows.Controls.StyleSelector
{
    public Style FirstStyle { get; set; }
    public Style OtherStyles { get; set; }
    private int number;

    public override System.Windows.Style SelectStyle(object item, System.Windows.DependencyObject container)
    {
        return (number++) == 0 ? FirstStyle : OtherStyles;
    }
}

As a result you get
enter image description here

This solution can also be used if you want to change appearance of odd/even tabitem. In order to acquire this do following change

 return (number++) % 2 == 0 ? FirstStyle : OtherStyles;

enter image description here

Maximus
  • 3,458
  • 3
  • 16
  • 27
1

You will need to handle the TabControl.SelectionChanged Event and programmatically set the Style after checking if the selected TabItem is your first TabItem. You could try something like this:

private void TabControlSelectionChanged(object sender, SelectionChangedEventArgs args)
{
    TabItem tabItem = ((sender as TabControl).SelectedItem as TabItem);
    if (tabItem.Name == "1stTabItem") tabItem.Style = (Style)Resources["FirstTabItem"];
    else tabItem.Style = (Style)Resources["NormalTabItem"];
}

UPDATE >>>

So things have changed now that you've finally told us that you're using MVVM. Most MVVM developers would blindly like to follow a no code behind principle without understanding it at all. For UI related work like this, it is absolutely fine to use the code behind, perhaps even more correct than putting UI properties into your view model.

However, if you really don't want to use the code behind, then you still have a few other options. One option is to simply data bind to the SelectedItem property and do your stuff in the property setter like in my answer to the Selection changed event of combobox in wpf mvvm (from the linked answer):

public SomeType Item 
{
    get { return item; }
    set
    {
        if (item != value)
        {
            item = value;
            NotifyPropertyChanged("Item");
            // New item has been selected. Do something here
        }
    }
}

However, you won't have access to the Resources collection from the view model, so this isn't much use to you. Another option would be to wrap your required event in an Attached Property and put your Style setting code in there. You can find an example of wrapping an event with an Attached Property and other useful links in my answer to the What's the best way to pass event to ViewModel? question.

Community
  • 1
  • 1
Sheridan
  • 68,826
  • 24
  • 143
  • 183
  • That's an excellent one. I probably should have mentioned this in my post but I am using MVVM pattern. Is there a way to get the selection changed event to the view model and then process it there? – Much Overflow Sep 01 '14 at 12:21
  • 1
    *I probably should have mentioned this in my post but I am using MVVM pattern*... there's no probably about it... you *should* have mentioned it. Would you go to buy a car with out telling them the colour? – Sheridan Sep 01 '14 at 12:49