Dynamically change text color of tabs

Docking/MDI for WPF Forum

Posted 2 years ago by Grace
Version: 16.1.0635
Avatar

I have several tabs for DocumentWindows and ToolWindows that are generated dynamically. The color and the font color of these tabs need to change at certain times (when they are selected/unselected, when the theme changes). I have been unable to change the font color of the tabs and have only been able to change the tab color through the TabTintColor property.

All of the windows are generated dynamically in the code behind; there are no DocumentWindows or ToolWindows in the xaml for this page.

The color and font color of the tabs each bind to one of two propeties, (selected tab/text, unselected tab/text) and the text shown on the tab must bind to the Title property on the window.

What is the best way to dynamically change the background color and text color for these dynamically generated tabs?

Comments (19)

Posted 2 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar

Hi Grace,

Does the DockingWindow.TabTintColor property work for you?  That would allow you to set a single color for a tab and it will handle selected variations for you.  The foreground text needs to be white though to look good on the variations and have the appearance remain consistent.

If you need further customization though, you'd have to clone our default AdvancedTabItem Style and update the Template property using what we discussed in the other recent thread with you.  In an updated Template you could possibly bind the border background and text foreground to various Brush attached properties you set on the AdvancedTabItem.  This Style could probably also have Setters that bind the same Brush attached property values from the DockingWindow (which should be the data context).  That way if you set the attached properties on the DockingWindow, it would flow down to the AdvancedTabItem (via the Setter Binding) and then the AdvancedTabItem modified Template would use the attached properties to alter the appearance.  This option is more complex but our product is designed to fully support custom templates if you want to alter how we did things.


Actipro Software Support

Posted 2 years ago by Grace
Avatar

The TabTintColor works, but ideally we'd like to be able to control how the tab color changes for various events. It looks like the AdvancedTabItem will do most of what we want.

Is there any way to change the TabTintColor behavior for each of it's events (GotFocus, Click, LostFocus, etc)?

Posted 2 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar

Hi Grace,

No, the TabTintColor just modifies our other brushes to be tinted with that particular color.  If you want the fine-grained control, you'd need to do what I mentioned earlier about making a new Style for AdvancedTabItem.  That will let you have full control over the appearance in various states.  Since your company has WPF Studio, you can download the default styles/templates from your account on our web site.


Actipro Software Support

Posted 2 years ago by Grace
Avatar

I have been trying to implement the TabItemContainerStyle xaml code suggested, but I can't get the binding to work. Am I missing something?

Also, what properties on AdvancedTabItem can I target to change the tab's color? I have tried all of the BorderBrush and Background options that are properties of AdvancedTabItem, but none of them change the color. 

Answer - Posted 2 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar

There are a bunch of properties on AdvancedTabItem for Brushes to use in various states and our default template uses those, however code in AdvancedTabControl.PrepareContainerForItemOverride binds those to related Tab* properties set on the AdvancedTabControl itself.  That makes it really easy to customize a look of an entire tab control but won't work for individual tabs needing to be different.

So you'd need to make a custom style/template for the tab items.  Below is a quick (and ugly) sample of customizing the tab item template.  Instead of using fixed color values like I do, you could use bindings in those Setter values.

xmlns:docking="http://schemas.actiprosoftware.com/winfx/xaml/docking"
xmlns:shared="http://schemas.actiprosoftware.com/winfx/xaml/shared"
xmlns:sampleBrowser="clr-namespace:ActiproSoftware.SampleBrowser"
xmlns:system="clr-namespace:System;assembly=mscorlib"

...

<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
<shared:ConditionalConverter x:Key="BooleanToOpacityConverter">
	<shared:ConditionalConverter.TrueValue>
		<system:Double>1</system:Double>
	</shared:ConditionalConverter.TrueValue>
	<shared:ConditionalConverter.FalseValue>
		<system:Double>0</system:Double>
	</shared:ConditionalConverter.FalseValue>
</shared:ConditionalConverter>
<docking:TitleConverter x:Key="TitleConverter" />
<shared:ThicknessConverter x:Key="ThicknessConverter" />

...

<docking:DockSite x:Name="dockSite">
	<docking:Workspace>
		<docking:TabbedMdiHost>
			<docking:TabbedMdiHost.TabItemContainerStyle>
				<Style TargetType="docking:AdvancedTabItem">
					<Setter Property="Header" Value="{Binding TabTextResolved, Converter={StaticResource TitleConverter}}" />
					<Setter Property="HeaderTemplate">
						<Setter.Value>
							<DataTemplate>
								<TextBlock Text="{Binding}" TextTrimming="None" TextWrapping="NoWrap" VerticalAlignment="Center" />
							</DataTemplate>
						</Setter.Value>
					</Setter>
						
					<Setter Property="Template">
						<Setter.Value>
							<ControlTemplate TargetType="docking:AdvancedTabItem">
								<Grid Background="Transparent">
									<docking:TabItemBorder x:Name="TabChrome" IsSelected="{TemplateBinding IsSelected}"
																		TabStripPlacement="{TemplateBinding TabStripPlacement}" 
																		NearSlantExtent="{TemplateBinding NearSlantExtent}" FarSlantExtent="{TemplateBinding FarSlantExtent}"
																		BorderThickness="{TemplateBinding BorderThickness}" UntintedBorderBrush="{TemplateBinding BorderBrush}" 
																		UntintedBackground="{TemplateBinding Background}" CornerRadius="{TemplateBinding CornerRadius}"
																		TintColor="{TemplateBinding TintColor}" FlashColor="{TemplateBinding FlashColor}" FlashMode="{TemplateBinding FlashMode}">
										<Grid>
											<Grid.ColumnDefinitions>
												<ColumnDefinition Width="Auto" />
												<ColumnDefinition Width="*" />
												<ColumnDefinition Width="Auto" />
												<ColumnDefinition Width="Auto" />
											</Grid.ColumnDefinitions>

											<Image AutomationProperties.Name="Image" Width="16" Height="16" Stretch="Uniform" Source="{TemplateBinding ImageSource}"
													Margin="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Padding, Converter={StaticResource ThicknessConverter}, ConverterParameter='Left'}"
													Visibility="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsImageVisible, Converter={StaticResource BooleanToVisibilityConverter}}"
													VerticalAlignment="Center" SnapsToDevicePixels="True" />

											<shared:PixelSnapper Grid.Column="1" VerticalRoundMode="CeilingToEven">
												<ContentPresenter x:Name="ContentPresenter" Margin="{TemplateBinding Padding}" 
																	Content="{TemplateBinding Header}" ContentTemplate="{TemplateBinding HeaderTemplate}"
																	TextElement.Foreground="{TemplateBinding Foreground}"
																	HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
													<ContentPresenter.Resources>
														<Style TargetType="TextBlock">
															<Setter Property="TextTrimming" Value="CharacterEllipsis" />
															<Setter Property="TextWrapping" Value="NoWrap" />
														</Style>
													</ContentPresenter.Resources>
												</ContentPresenter>
											</shared:PixelSnapper>
								
											<shared:PixelSnapper Grid.Column="2" VerticalRoundMode="CeilingToEven">
												<ContentControl x:Name="ContextContentControl" IsTabStop="False"
																Content="{TemplateBinding ContextContent}" ContentTemplate="{TemplateBinding ContextContentTemplate}" 
																TextElement.Foreground="{Binding ElementName=ContentPresenter, Path=(TextElement.Foreground)}" VerticalAlignment="Center" />
											</shared:PixelSnapper>
								
											<StackPanel x:Name="ButtonPanel" Grid.Column="3" Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
												<Button x:Name="ToggleLayoutKindButton" ContentTemplate="{TemplateBinding PinButtonContentTemplate}" Style="{TemplateBinding EmbeddedButtonStyle}" 
														Command="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ToggleLayoutKindCommand}"
														Foreground="{Binding ElementName=ContentPresenter, Path=(TextElement.Foreground)}" 
														Visibility="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=HasToggleLayoutKindButton, Converter={StaticResource BooleanToVisibilityConverter}}"
														Opacity="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsToggleLayoutKindButtonVisible, Converter={StaticResource BooleanToOpacityConverter}}"
														ToolTip="{docking:SRExtension UIAdvancedTabItemToggleLayoutKindButtonToolTip}" AutomationProperties.Name="Toggle Layout Kind" />
												<Button x:Name="CloseButton" ContentTemplate="{TemplateBinding CloseButtonContentTemplate}" Style="{TemplateBinding EmbeddedButtonStyle}" 
														Command="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=CloseCommand}"
														Foreground="{Binding ElementName=ContentPresenter, Path=(TextElement.Foreground)}" 
														Visibility="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=HasCloseButton, Converter={StaticResource BooleanToVisibilityConverter}}"
														Opacity="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsCloseButtonVisible, Converter={StaticResource BooleanToOpacityConverter}}"
														ToolTip="{docking:SRExtension UIAdvancedTabItemCloseButtonToolTip}" AutomationProperties.Name="Close" />
											</StackPanel>
										</Grid>
									</docking:TabItemBorder>
								</Grid>
					
								<ControlTemplate.Triggers>
									<Trigger Property="IsReadOnly" Value="True">
										<Setter TargetName="ContextContentControl" Property="ContentTemplate" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ReadOnlyContextContentTemplate}" />
									</Trigger>
									<Trigger Property="LayoutKind" Value="Pinned">
										<Setter TargetName="ToggleLayoutKindButton" Property="ContentTemplate" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=UnpinButtonContentTemplate}" />
									</Trigger>
									<Trigger Property="HighlightKind" Value="PointerOver">
										<Setter TargetName="TabChrome" Property="UntintedBackground" Value="LightGreen" />
										<Setter TargetName="TabChrome" Property="UntintedBorderBrush" Value="Green" />
										<Setter TargetName="ContentPresenter" Property="TextElement.Foreground" Value="Black" />
									</Trigger>
									<Trigger Property="HighlightKind" Value="ActiveSelected">
										<Setter TargetName="TabChrome" Property="UntintedBackground" Value="LightBlue" />
										<Setter TargetName="TabChrome" Property="UntintedBorderBrush" Value="Blue" />
										<Setter TargetName="ContentPresenter" Property="TextElement.Foreground" Value="Black" />
									</Trigger>
									<Trigger Property="HighlightKind" Value="InactiveSelected">
										<Setter TargetName="TabChrome" Property="UntintedBackground" Value="Transparent" />
										<Setter TargetName="TabChrome" Property="UntintedBorderBrush" Value="#303030" />
										<Setter TargetName="ContentPresenter" Property="TextElement.Foreground" Value="#303030" />
									</Trigger>
								</ControlTemplate.Triggers>
							</ControlTemplate>
						</Setter.Value>
					</Setter>
				</Style>
			</docking:TabbedMdiHost.TabItemContainerStyle>
			
			<docking:TabbedMdiContainer>
				<docking:DocumentWindow Title="Document1.txt">
					<TextBox BorderThickness="0" />
				</docking:DocumentWindow>
				<docking:DocumentWindow Title="Document2.txt">
					<TextBox BorderThickness="0" />
				</docking:DocumentWindow>
				<docking:DocumentWindow Title="Document3.txt">
					<TextBox BorderThickness="0" />
				</docking:DocumentWindow>
			</docking:TabbedMdiContainer>
		</docking:TabbedMdiHost>
	</docking:Workspace>
		
</docking:DockSite>


Actipro Software Support

Posted 2 years ago by Grace
Avatar

This does exactly what I needed. Thanks!

Posted 2 years ago by Grace
Avatar

One last question, the AdvancedTabItem doesn't seem to work for ToolWindows. What should I use to cange the default styles of a ToolWindow's tab?

Posted 2 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar

Correct, the above is just for tabbed MDI since you are setting the TabbedMdiHost.TabItemContainerStyle.  There is a similar DockSite.ToolWindowTabItemContainerStyle property that applies to tool widnows.


Actipro Software Support

Posted 2 years ago by Grace
Avatar

I also need to change the styles for the tabs that show when the ToolWindow is hidden and for the ToolWindow's TitleBar. Is there a way to do this?

Posted 2 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar

Hi Grace,

Sorry but I'm not sure what you mean by tabs that show when a tool window is hidden.  In that case, there are no tabs visible.  Can you clarify?

For the title bar though, that is realized through the ToolWindowContainer style.  I think you could make a custom Style that targets ToolWindowContainer in your Application.Resources that clones our default one and alters the tltle bar if you like.


Actipro Software Support

Posted 2 years ago by Grace
Avatar

Sorry for the confusion, I mean the controls that are used to toggle between hide and show when the ToolWindow when it is in auto-hide mode. It has the window's title written sideways with a vertical bar behind the text.

Posted 2 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar

Oh I see, yes that's the auto-hide tabs.  The DockSite.AutoHideTabItemTemplate has the default DataTemplate that is used.  There is a AutoHideTabItemTemplateSelector property too if you want a DataTemplateSelector.  As for the Style of those tabs, you'd have to make an implicit Style for AutoHideTabItem and put it in your Application.Resources.


Actipro Software Support

Posted 2 years ago by Grace
Avatar

I was able to get the AutoHideTabItemTemplate to work for the most part.

The Style for the ToolWindowContainer doesn't seem to binding correctly. I tried some very simple properties that should work to see if it was working and saw no change when I ran the program. I tried defining the style in the App.Xaml and in the container, but neither worked.

This is an example of what I have right now, is there another way I should be doing this?

<docking:ToolWindowContainer SnapsToDevicePixels="True" TitleFontSize="12" TitleFontWeight="Bold">
                                <docking:ToolWindowContainer.Style>
                                    <Style TargetType="docking:ToolWindowContainer">
                                        <Setter Property="BorderBrush" Value="BlueViolet"/>
                                        <Setter Property="BorderThickness" Value="5"/>
                                    </Style>
                                </docking:ToolWindowContainer.Style>
                            </docking:ToolWindowContainer>
Posted 2 years ago by Grace
Avatar

I got the ToolWindowContainer to work for when the ToolWindow is in AutoHide mode, but it isn't working for docked mode.

Posted 2 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar

You should never set properties directly on any *Container in Docking/MDI.  All container-named types are objects that get created/destroyed as layout changes happen.  Instead, make an implicit Style as mentioned in my previous reply that targets the ToolWindowContainer type and put that in your Application.Resources.


Actipro Software Support

Posted 2 years ago by Grace
Avatar

I moved it into the Application.Resources but it still isn't working for when the window is docked. I'm using the trigger for when State is Docked, is there another trigger I should use?

Posted 2 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar

Hi Grace,

I just tested this simple implicit Style in Application.Resources and ToolWindowContainers in docked state (as compared to those in the auto-hide popup) show up as red ok:

<Style TargetType="docking:ToolWindowContainer">
	<Setter Property="Template">
		<Setter.Value>
			<ControlTemplate TargetType="docking:ToolWindowContainer">
				<Button x:Name="button">ToolWindowContainer</Button>
							
				<ControlTemplate.Triggers>
					<Trigger Property="State" Value="Docked">
						<Setter TargetName="button" Property="Background" Value="Red" />
					</Trigger>
				</ControlTemplate.Triggers>
			</ControlTemplate>
		</Setter.Value>
	</Setter>
</Style>


Actipro Software Support

Posted 2 years ago by Grace
Avatar

I tried this, but docking the window completely changes the style. The ToolWindowContainers are nested inside of DockSite and AutoHideLeftContainers or AutoHideRightContainers. The style isn't getting set anywhere else in the xaml or code behind. What could be causing the style to change when the window is docked?

Posted 2 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar

Hi Grace,

Since this is a scenario-based question and we aren't seeing what you are, please make a new simple sample project that shows the issue and email it to our support address.  In your email, reference this thread and be sure to rename the .zip file extension of what you send so it doesn't get spam blocked.  Then we'll have a look at what is going on.  Thanks!


Actipro Software Support

The latest build of this product (v2019.1 build 0681) was released 1 month ago, which was after the last post in this thread.

Add Comment

Please log in to a validated account to post comments.