user2023653
user2023653

Reputation:

WPF styling TabControl TabItems custom Foreground/Background colors

I'm pretty new to WPF -- tantalized by the possibilities, but getting frustrated.... I'm trying to make it so different tabs on a TabControl have different foregound/background colors according to when they're selected. First thing I did was to create new TabItem class called PlayerTabItem and gave it a Brush SelectedBackground property. This is a music player app, so "player" in this context refers to its use in this app. (I first created SelectedBackground as a simple property, then later as a dependency property, but this didn't seem to change anything, so I have omitted that implementation.)

class PlayerTabItem : TabItem
{
    public Brush SelectedBackground { get; set; }
}

Then I used this is in my XAML, and it compiled okay (so long as I put "local:" in front of the tag name), and recognized the new property I created. Of course, the property didn't do anything. This is where I got stuck.

<local:PlayerTabItem Header="Now Playing" SelectedBackground="Blue"/>
<local:PlayerTabItem Header="Collection" SelectedBackground="Purple"/>
<local:PlayerTabItem Header="Search" SelectedBackground="Green"/>

I tried handling selection events in the PlayerTabItem class in order to apply the background color, but this was a dead end. (Overriding PlayerTabItem.OnSelected and setting color there had no effect -- ran without error but did nothing.) Then I tried adding a Style with a new ControlTemplate and a Trigger for IsSelected = true, and I started getting closer....it worked if I just hard-coded a color in the Trigger.Setter:

<Trigger Property="IsSelected" Value="True">
   <Setter TargetName="Panel" Property="Background" Value="Purple" />
</Trigger>

But what I really want is to bind to the PlayerTabItem's SelectedBackground color. I tried this:

<Setter TargetName="Panel" Property="Background" Value="{Binding SelectedBackground}" />

But it had no effect. I suspected that I needed some kind of Path argument on the binding, but I had no idea what. I tried using XAMLSpy to maybe help me see what was going on (as far as hierarchy of elements and possible binding path), but I didn't get very far with that -- except that when I tried to set the SelectedBackground property through XAMLSpy, it reported that the property SelectedBackground wasn't found. How could that be? ....since I had compiled and run the program without error.

I hope what I'm trying to do makes sense -- I just want to change the background color of selected tabs on a tab control when they are selected.

Upvotes: 0

Views: 1176

Answers (1)

Emmanuel DURIN
Emmanuel DURIN

Reputation: 4913

  1. In order to have the tab color to change, edit the template control, and remove the triggers :
    In outline window right click on the PlayerTabItem : Edit Template/Edit a copy.
    You could also modify the triggers to apply some style depending on focus, hover, ...

  2. First create two dependency properties (snippet propdp + tabulation twice) in the PlayerTabItem, and listen to the changes of the IsSelected property:

    class PlayerTabItem : TabItem
    {
        public PlayerTabItem()
        {
            Loaded += (sender, e) => { Background = IsSelected ? SelectedBackground : UnSelectedBackground; };
            DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(TabItem.IsSelectedProperty, typeof(TabItem));
            dpd.AddValueChanged(this, (sender, args) =>
            {
                Background = IsSelected ? SelectedBackground : UnSelectedBackground;
                System.Diagnostics.Debug.WriteLine("Changing background of {0} to {1}", this.Header, this.Background);
            });
        }
        public Brush SelectedBackground
        {
            get { return (Brush)GetValue(SelectedBackgroundProperty); }
            set { SetValue(SelectedBackgroundProperty, value); }
        }
        public static readonly DependencyProperty SelectedBackgroundProperty =
            DependencyProperty.Register("SelectedBackground", typeof(Brush), typeof(PlayerTabItem), new PropertyMetadata(null));
        public Brush UnSelectedBackground
        {
            get { return (Brush)GetValue(UnSelectedBackgroundProperty); }
            set { SetValue(UnSelectedBackgroundProperty, value); }
        }
        public static readonly DependencyProperty UnSelectedBackgroundProperty =
            DependencyProperty.Register("UnSelectedBackground", typeof(Brush), typeof(PlayerTabItem), new PropertyMetadata(null));
    }
    
  3. So the controls can be declared using the dependency properties and see the color change when selection is made

    <TabControl >
        <local:PlayerTabItem SelectedBackground="Red" UnSelectedBackground="Pink"  Header="Tab1" Style="{DynamicResource PlayerTabItemStyle1}" />
        <local:PlayerTabItem SelectedBackground="Yellow" UnSelectedBackground="Pink" Header="Tab2" Style="{DynamicResource PlayerTabItemStyle1}"/>
        <local:PlayerTabItem SelectedBackground="Green" UnSelectedBackground="Pink" Header="Tab3" Style="{DynamicResource PlayerTabItemStyle1}"/>
    </TabControl>
    

I admit that there must be a better to do it without listening to the events, just using the triggers. But I couldn't get it to work.

Note that in my sample, the colors are simple (red,...) but you could use any brush for the colors

There is a full working demo in the link here : http://1drv.ms/1NfCl9z

Best coding

Upvotes: 0

Related Questions