I am currently working on a Plug-In for AutoCAD, scripting language is VB.net.
Basically I have a User Control which holds a TabControl, each TabItem is an object which just holds the TabItem.Header and TabItem.Content definition. The TabItems are generated dynamically through a xml file. As I am using MVVM this is all stored in an ObservableCollection which is bound to the TabControl items.
As I am fighting with MVVM a little bit and I am rather new to WPF I need a little guidance on the following task: Everything is working fine so far but the only problem I have is that I want a little button at the end of the visible TabItems. When I click on it I can switch through all the Tabs, doesn't matter if they are visible or not.
For a better undertstanding, this should be the desired result:
Image File
I just want a simple explanation on how to achieve that (all the samples on the net are rather complex to me). I tried it with a ScrollViewer, but the result is bad. Here is the current code:
TabControl Template:
<Style x:Key="TabControl"
TargetType="{x:Type TabControl}">
<Setter Property="Background"
Value="{StaticResource TabBackground}">
</Setter>
<Setter Property="BorderBrush"
Value="{StaticResource TabItemActiveBorder}">
</Setter>
<Setter Property="BorderThickness"
Value="0,1,1,0">
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<StackPanel>
<ScrollViewer HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Visible">
<TabPanel x:Name="HeaderPanel"
Panel.ZIndex="1"
KeyboardNavigation.TabIndex="1"
Grid.Column="0"
Grid.Row="0"
Margin="2,2,2,0"
IsItemsHost="true" />
</ScrollViewer>
<ContentPresenter x:Name="PART_SelectedContentHost"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
Margin="{TemplateBinding Padding}"
ContentSource="SelectedContent" />
</StackPanel>
<!--<Grid>
<Grid.RowDefinitions KeyboardNavigation.TabNavigation="Local">
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ScrollViewer>
<TabPanel x:Name="HeaderPanel"
Panel.ZIndex="1"
Margin="0,0,4,-1"
IsItemsHost="True"
KeyboardNavigation.TabIndex="1"
Background="Transparent" />
</ScrollViewer>
</Grid>-->
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="TabItem"
TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid>
<Border Name="Border"
Margin="0,-2,5,0"
Padding="0,1,0,1"
Height="55"
BorderBrush="{StaticResource TabItemActiveBorder}"
CornerRadius="0,5,5,0">
<ContentPresenter x:Name="ContentSite"
VerticalAlignment="Center"
HorizontalAlignment="Center"
ContentSource="Header"
Margin="2,5,2,5"
RecognizesAccessKey="True" />
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected"
Value="True">
<Setter Property="Panel.ZIndex"
Value="100" />
<Setter TargetName="Border"
Property="Margin"
Value="-1,-2,1,0" />
<Setter Property="TextElement.Foreground"
Value="{StaticResource TabItemActiveText}" />
<Setter TargetName="Border"
Property="Background"
Value="{StaticResource TabBackground}" />
<Setter TargetName="Border"
Property="BorderThickness"
Value="0,1,1,1" />
</Trigger>
<Trigger Property="IsSelected"
Value="false">
<Setter Property="TextElement.Foreground"
Value="{StaticResource TabItemInactiveText}" />
<Setter TargetName="Border"
Property="Background"
Value="{StaticResource TabItemInactiveBackground}" />
<Setter TargetName="Border"
Property="BorderThickness"
Value="0,1,1,1" />
</Trigger>
<Trigger Property="IsEnabled"
Value="False">
<Setter TargetName="Border"
Property="Background"
Value="{StaticResource InActiveControlBackGround}" />
<Setter TargetName="Border"
Property="BorderBrush"
Value="{StaticResource InActiveControlBackGround}" />
<Setter Property="Foreground"
Value="{StaticResource InActiveControlBackGround}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<ContentPresenter Content="{TemplateBinding Content}">
<ContentPresenter.LayoutTransform>
<RotateTransform Angle="270" />
</ContentPresenter.LayoutTransform>
</ContentPresenter>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
mainWindow XAML excerpt:
<Grid Background="{StaticResource TabBackground}">
<Grid Margin="0,96,0,0">
<TabControl ItemContainerStyle="{StaticResource TabItem}"
TabStripPlacement="Right"
ItemsSource="{Binding loadedPalettes}"
Style="{StaticResource TabControl}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Header}">
<TextBlock.LayoutTransform>
<RotateTransform Angle="270" />
</TextBlock.LayoutTransform>
</TextBlock>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<UserControls:tabDataGrid />
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</Grid>
TabItem Class:
Private Property _Header As String
Public Property Header As String
Get
Return _Header
End Get
Set(value As String)
_Header = value
End Set
End Property
Private Property _Content As String
Public Property Content As String
Get
Return _Content
End Get
Set(value As String)
_Content = value
End Set
End Property
Thanks in advance!
I solved the problem by myself. Here is the working piece of template code:
<Style x:Key="TabControl"
TargetType="{x:Type TabControl}">
<Setter Property="Background"
Value="{StaticResource TabBackground}">
</Setter>
<Setter Property="BorderBrush"
Value="{StaticResource TabItemActiveBorder}">
</Setter>
<Setter Property="BorderThickness"
Value="0,1,1,0">
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ScrollViewer HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden"
Grid.Column="1"
Grid.Row="0">
<TabPanel x:Name="HeaderPanel"
Panel.ZIndex="1"
Margin="0,2,2,2"
IsItemsHost="True"
Background="Transparent" />
</ScrollViewer>
<ContentPresenter x:Name="PART_SelectedContentHost"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
Margin="{TemplateBinding Padding}"
ContentSource="SelectedContent" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Related
How can I change only the foreground color of a TabItem header text when it is selected or active without changing the foreground of any item inside that TabItemor anything? I'm new to all this so finding it difficult to figure out where in my TabItemstyling can I implement this little feature and how.
The TabControl style I'm using is:
<Style
x:Key="{x:Type TabControl}"
TargetType="{x:Type TabControl}">
<Setter
Property="BorderThickness"
Value="0" />
<Setter
Property="BorderBrush"
Value="Transparent" />
<Setter
Property="Background"
Value="Transparent" />
<Setter
Property="Template">
<Setter.Value>
<ControlTemplate
TargetType="TabControl">
<Grid>
<Grid.RowDefinitions>
<RowDefinition
Height="Auto" />
<RowDefinition
Height="*" />
</Grid.RowDefinitions>
<Border
BorderThickness="0,0,1,1"
BorderBrush="#D0CEBF"
Grid.Row="1">
<Border
BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}">
<Border
Background="{TemplateBinding Background}">
<ContentPresenter
ContentSource="SelectedContent" />
</Border>
</Border>
</Border>
<TabPanel
Grid.Row="0"
IsItemsHost="true"
HorizontalAlignment="Center" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style
TargetType="TabItem">
<Setter
Property="BorderThickness"
Value="0" />
<Setter
Property="BorderBrush"
Value="Transparent" />
<Setter
Property="Background"
Value="Transparent" />
<Setter
Property="VerticalContentAlignment"
Value="Center" />
<Setter
Property="HorizontalContentAlignment"
Value="Center" />
<Setter
Property="Template">
<Setter.Value>
<ControlTemplate
TargetType="{x:Type TabItem}">
<!--In order to click on the blank part of the TabItem can be successfully selected-->
<Border
Background="Transparent">
<Grid>
<Grid
x:Name="g">
<Path
Fill="{TemplateBinding Background}"
Margin="0,0,0,-1"
Data="M 20,40 L 0,40 0,40 C 4,40 10,36 10,30 L 10,10 C 10,0 16,0 20,0 L 155,0 C 165,0 173,0 ,175,6 L175,30 C 175,30 175,38 182,40 Z" />
</Grid>
<Border
BorderThickness="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}">
<ContentPresenter
ContentSource="Header"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Border>
</Grid>
</Border>
<!--Add ControlTemplate.Triggers to change the background color of the selected TabItem.-->
<ControlTemplate.Triggers>
<Trigger
Property="IsSelected"
Value="false">
<Setter
Property="Visibility"
TargetName="g"
Value="Hidden" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Adding a trigger in your TabItem control template unfortunately sets the foreground color of the TabItem content, too, when the tab is selected, so this does not work.
<Trigger Property="IsSelected" Value="True">
<Setter Property="Foreground" Value="Red" />
</Trigger>
However, you could add an implicit TextBlock style (without x:Key) inside the ContentPresenter resources. It will be applied automatically only to TextBlocks inside of its scope, not affecting the TabItem content or even other elements in a custom header template other than TextBlocks.
<ContentPresenter
ContentSource="Header"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" >
<ContentPresenter.Resources>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger
Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType={x:Type TabItem}}}"
Value="true">
<Setter
Property="Foreground"
Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentPresenter.Resources>
</ContentPresenter>
Alternatively, a specialized solution is to create a header template and put the trigger there. In this case it does not force an overridden header template to apply the foreground to each TextBlock.
<Setter
Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding}">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger
Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType={x:Type TabItem}}}"
Value="true">
<Setter
Property="Foreground"
Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</DataTemplate>
</Setter.Value>
</Setter>
I have a TabControl that displays a different Tab header foreground and background for a selected tab. But I would like to set a general foreground color for TextBlocks within the tab item content control. What is happening instead is all the headers are getting the general TextBlock foreground color and the tab control is not changing the foreground color for the header when the tab is selected.
So in my main window I have:
<Grid>
<TabControl Style="{StaticResource TabControlStyle}">
<TabItem Header="Tab 1" IsSelected="True">
<TextBlock Text="Text in Tab 1"/>
</TabItem>
<TabItem Header="Tab 2">
<TextBlock Text="Text in Tab 2"/>
</TabItem>
</TabControl>
</Grid>
and in my resource file I have defined my colors and content templates:
<Color x:Key="DarkGray">#404040</Color>
<Color x:Key="DarkGreen">#3A5038</Color>
<Color x:Key="ForegroundColor">#FFF1F1F1</Color>
<SolidColorBrush x:Key="DarkGrayBrush"
Color="{StaticResource DarkGray}" />
<SolidColorBrush x:Key="ForegroundColorBrush"
Color="{StaticResource ForegroundColor}" />
<SolidColorBrush x:Key="DarkGreenBrush"
Color="{StaticResource DarkGreen}" />
<Style TargetType="TextBlock">
<Setter Property="Foreground"
Value="{StaticResource DarkGrayBrush}" />
</Style>
<Style x:Key="TabControlStyle"
TargetType="TabControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TabControl">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TabPanel Grid.Row="0"
Background="{TemplateBinding Background}"
IsItemsHost="true" />
<ContentPresenter Grid.Row="1"
ContentSource="SelectedContent" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Resources>
<Style TargetType="TabItem">
<Setter Property="BorderThickness"
Value="0" />
<Setter Property="FontSize"
Value="16" />
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<Border>
<ContentPresenter Content="{TemplateBinding Content}" />
</Border>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TabItem">
<Border Name="Border"
Width="145"
Margin="10"
Padding="0"
BorderThickness="0"
CornerRadius="20">
<ContentPresenter x:Name="ContentSite"
Margin="10"
HorizontalAlignment="Center"
VerticalAlignment="Center"
ContentSource="Header" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected"
Value="True">
<Setter TargetName="Border"
Property="Background"
Value="{StaticResource DarkGreenBrush}" />
<Setter Property="Foreground"
Value="{StaticResource ForegroundColorBrush}" />
</Trigger>
<Trigger Property="IsSelected"
Value="False">
<Setter Property="Foreground"
Value="{StaticResource DarkGrayBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Style.Resources>
</Style>
I am targeting .NET 4.5 on a Windows 10 operating system.
Thanks, Will
Set the TextBlock.Foreground property of the ContentPresenter:
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TabItem">
<Border Name="Border"
Width="145"
Margin="10"
Padding="0"
BorderThickness="0"
CornerRadius="20">
<ContentPresenter x:Name="ContentSite"
Margin="10"
HorizontalAlignment="Center"
VerticalAlignment="Center"
ContentSource="Header" TextBlock.Foreground="{StaticResource DarkGrayBrush}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="Border"
Property="Background"
Value="{StaticResource DarkGreenBrush}" />
<Setter TargetName="ContentSite" Property="TextBlock.Foreground"
Value="{StaticResource ForegroundColorBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<TabControl x:Class="MyTabControl.Tab_Control"
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"
xmlns:local="clr-namespace:MyTabControl" Padding="0" Background="White" BorderBrush="Black" Loaded="TabControl_Loaded">
<TabControl.Resources>
<Style TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid Name="Grid_Main">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Border Grid.Column="1" Name="border_Main" Background="#F0F0F0" BorderBrush="LightGray" BorderThickness="1,1,1,0" CornerRadius="4,4,0,0"
Margin="-2,0,2,0" SnapsToDevicePixels="True" >
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="13" HorizontalAlignment="Center" Name="TextBlock"
Foreground="DarkGray">
<ContentPresenter x:Name="ContentSite" VerticalAlignment="Center"
HorizontalAlignment="Center" ContentSource="Header" Margin="5,2,5,2"/></TextBlock>
</StackPanel>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="border_Main" Property="Background" Value="White" />
<Setter TargetName="border_Main" Property="BorderBrush" Value="Gray" />
<Setter TargetName="TextBlock" Property="Foreground" Value="Black" />
<Setter TargetName="border_Main" Property="Margin" Value="-2,0,2,-1" />
</Trigger>
<Trigger Property="IsMouseOver" Value="True" SourceName="border_Main" >
<Setter TargetName="border_Main" Property="Background" Value="White" />
<Setter TargetName="border_Main" Property="BorderBrush" Value="DarkGray" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</TabControl.Resources>
</TabControl>
How can I access my "border_Main" control programmatically?
I would recommend using LinqToVisualTree ...
http://www.scottlogic.co.uk/blog/colin/2010/03/linq-to-visual-tree/
You can find all the "border_Main" controls within the TabControl as follows:
tabControl.Descendants<Border>().Where(d => d.Name=="border_Main");
Or, if you could use the above query on a TabItem directly if you want to find a single border_Main instance.
I have created a custom style for my WPF datagrid by overriding its control template - nothing unusual, just copied the original template and modified it. Unfortunately, when the grid is drawn, the fully qualified class name of my ViewModel is showing up in the header (the ViewModel happens to be the DataContext of the UserControl that contains the DataGrid). Using Snoop, I have narrowed down which element in the template is showing this class name:
<DataGridColumnHeadersPresenter
Grid.Column="1"
Name="PART_ColumnHeadersPresenter"
Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=HeadersVisibility, Converter={x:Static DataGrid.HeadersVisibilityConverter}, ConverterParameter={x:Static DataGridHeadersVisibility.Column}}"/>
The visual tree for this part looks like this:
PART_ColumnHeadersPresenter (DataGridColumnHeadersPresenter)
(Grid)
headerBorder (DataGridHeaderBorder)
(Border)
(TextBlock)
It is this text block that contains the class name! So the questions are
Why does the Border need a TextBlock?
Why is the TextBlock initialized with the class name of the DataContext?
Is there a property at the DataGrid level that controls the conent of this TextBlock?
P.S. To answer the comment below, I am specifying proper paths for the ItemSource and also for each column:
<DataGrid
ItemsSource="{Binding Path=Orders, Mode=TwoWay}"
AutoGenerateColumns="False"
IsReadOnly="True">
<DataGrid.Columns>
<DataGridTextColumn
Header="Creation Time"
Binding="{Binding Path=CreationTime}"
CellStyle="{StaticResource LeftAlignedCellStyle}"
SortMemberPath="CreationTime">
</DataGridTextColumn>
...
</DataGrid.Columns>
</DataGrid>
I don't see any place where I must bind the TextBlock for the column header border. Don't even know how it makes sense!
Based on Avatar's comment, I am sharing my entire template. See below:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Classic">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Brushes.xaml"/>
</ResourceDictionary.MergedDictionaries>
<!-- ColumnHeader Gripper Style -->
<Style x:Key="ColumnHeaderGripperStyle" TargetType="{x:Type Thumb}">
<Setter Property="Width" Value="8"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Cursor" Value="SizeWE"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<Border Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}">
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- DataGridColumnHeader Style -->
<Style x:Key="DataGridColumnHeaderStyle" TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="Background" Value="{StaticResource HeaderBackgroundBrush}"/>
<Setter Property="Foreground" Value="{StaticResource HeaderForegroundBrush}"/>
<Setter Property="BorderBrush" Value="{StaticResource HeaderBorderBrush}" />
<Setter Property="BorderThickness" Value="0,1,0,1" />
<Setter Property="FontFamily" Value="Trebuchet MS" />
<Setter Property="FontSize" Value="12" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
<Grid>
<themes:DataGridHeaderBorder
x:Name="headerBorder"
SortDirection="{TemplateBinding SortDirection}"
IsHovered="{TemplateBinding IsMouseOver}"
IsPressed="{TemplateBinding IsPressed}"
IsClickable="{TemplateBinding CanUserSort}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Padding ="{TemplateBinding Padding}"
SeparatorVisibility="{TemplateBinding SeparatorVisibility}"
SeparatorBrush="{TemplateBinding SeparatorBrush}">
<Border BorderBrush="{StaticResource HeaderInnerBorderBrush}"
BorderThickness="0,1,0,0">
<TextBlock
Text="{Binding}" Margin="7,0,7,0"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" />
</Border>
</themes:DataGridHeaderBorder>
<Thumb x:Name="PART_LeftHeaderGripper"
HorizontalAlignment="Left"
Style="{StaticResource ColumnHeaderGripperStyle}"/>
<Thumb x:Name="PART_RightHeaderGripper"
HorizontalAlignment="Right"
Style="{StaticResource ColumnHeaderGripperStyle}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="headerBorder" Property="Background"
Value="{StaticResource HeaderHighlightedBackgoundBrush}" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="headerBorder" Property="Background"
Value="{StaticResource HeaderPressedBackgroundBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Right Aligned DataGridColumnHeader Style-->
<Style x:Key="RightAlignedColumnHeaderStyle"
TargetType="{x:Type DataGridColumnHeader}"
BasedOn="{StaticResource DataGridColumnHeaderStyle}">
<Setter Property="HorizontalContentAlignment" Value="Right"/>
</Style>
<!-- Center Aligned DataGridColumnHeader Style-->
<Style x:Key="CenterAlignedColumnHeaderStyle"
TargetType="{x:Type DataGridColumnHeader}"
BasedOn="{StaticResource DataGridColumnHeaderStyle}">
<Setter Property="HorizontalContentAlignment" Value="Center"/>
</Style>
<!-- DataGridRowHeader Gripper -->
<Style x:Key="RowHeaderGripperStyle" TargetType="{x:Type Thumb}">
<Setter Property="Height" Value="8"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Cursor" Value="SizeNS"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<Border Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- DataGridRowHeader Style -->
<Style x:Key="{x:Type DataGridRowHeader}"
TargetType="{x:Type DataGridRowHeader}">
<Setter Property="Background" Value="{StaticResource HeaderBackgroundBrush}" />
<Setter Property="BorderBrush" Value="{StaticResource HeaderBorderBrush}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridRowHeader}">
<Grid>
<themes:DataGridHeaderBorder
x:Name="headerBorder"
IsSelected="{TemplateBinding IsRowSelected}"
IsHovered ="{TemplateBinding IsMouseOver}"
IsPressed="{TemplateBinding IsPressed}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="1,0,1,1"
Padding ="{TemplateBinding Padding}"
Orientation="Horizontal"
SeparatorVisibility="{TemplateBinding SeparatorVisibility}"
SeparatorBrush="{TemplateBinding SeparatorBrush}">
<Border BorderBrush="{StaticResource HeaderInnerBorderBrush}"
BorderThickness="0,1,0,0">
<StackPanel Orientation="Horizontal">
<ContentPresenter
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="Center"/>
<Control
SnapsToDevicePixels="false"
Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGridRow}}, Path=(Validation.HasError), Converter={StaticResource bool2VisibilityConverter}}"
Template="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGridRow}}, Path=ValidationErrorTemplate}" />
</StackPanel>
</Border>
</themes:DataGridHeaderBorder>
<Thumb x:Name="PART_TopHeaderGripper"
VerticalAlignment="Top"
Style="{StaticResource RowHeaderGripperStyle}"/>
<Thumb x:Name="PART_BottomHeaderGripper"
VerticalAlignment="Bottom"
Style="{StaticResource RowHeaderGripperStyle}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="headerBorder" Property="Background"
Value="{StaticResource HeaderHighlightedBackgoundBrush}" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="headerBorder" Property="Background"
Value="{StaticResource HeaderPressedBackgroundBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- DataGridElement Styles -->
<Style x:Key="DataGridElementStyle" TargetType="{x:Type FrameworkElement}">
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Margin" Value="7 0 7 0" />
</Style>
<Style x:Key="LeftAlignedElementStyle" TargetType="{x:Type FrameworkElement}" BasedOn="{StaticResource DataGridElementStyle}">
<Setter Property="HorizontalAlignment" Value="Left" />
</Style>
<Style x:Key="CenterAlignedElementStyle" TargetType="{x:Type FrameworkElement}" BasedOn="{StaticResource DataGridElementStyle}">
<Setter Property="HorizontalAlignment" Value="Center" />
</Style>
<Style x:Key="RightAlignedElementStyle" TargetType="{x:Type FrameworkElement}" BasedOn="{StaticResource DataGridElementStyle}">
<Setter Property="HorizontalAlignment" Value="Right" />
</Style>
<!-- DataGridCell Styles -->
<Style x:Key="DataGridCellStyle" TargetType="{x:Type DataGridCell}">
<!-- Remove blue highlight when cell is selected -->
<Setter Property="Background" Value="Transparent" />
<!-- Don't change text color when cell is selected -->
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Foreground" Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=Foreground}"/>
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="LeftAlignedCellStyle" TargetType="{x:Type DataGridCell}" BasedOn="{StaticResource DataGridCellStyle}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Grid Background="{TemplateBinding Background}">
<ContentPresenter Style="{StaticResource LeftAlignedElementStyle}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Center Aligned DataGridCell Style -->
<Style x:Key="CenterAlignedCellStyle" TargetType="{x:Type DataGridCell}" BasedOn="{StaticResource DataGridCellStyle}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Grid Background="{TemplateBinding Background}">
<ContentPresenter Style="{StaticResource CenterAlignedElementStyle}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Right Aligned DataGridCell Style -->
<Style x:Key="RightAlignedCellStyle" TargetType="{x:Type DataGridCell}" BasedOn="{StaticResource DataGridCellStyle}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Grid Background="{TemplateBinding Background}">
<ContentPresenter Style="{StaticResource RightAlignedElementStyle}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- SelectAllButton ControlTemplate -->
<ControlTemplate x:Key="SelectAllButtonTemplate" TargetType="{x:Type Button}">
<Grid>
<Rectangle x:Name="Border" SnapsToDevicePixels="True"
Stroke="{StaticResource HeaderBorderBrush}"
Fill="{StaticResource HeaderBackgroundBrush}" />
<Border SnapsToDevicePixels="True" Margin="1,1,1,0"
BorderBrush="White" BorderThickness="0,1,0,0" />
<Polygon x:Name="Arrow"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Margin="8,8,3,3"
Opacity="0.15"
Fill="Black"
Stretch="Uniform"
Points="0,10 10,10 10,0" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Border" Property="Fill"
Value="{StaticResource HeaderHighlightedBackgoundBrush}" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="Border" Property="Fill"
Value="{StaticResource HeaderPressedBackgroundBrush}" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="Arrow" Property="Visibility" Value="Collapsed" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<!-- DataGrid Style -->
<Style x:Key="{x:Type DataGrid}" TargetType="{x:Type DataGrid}">
<Setter Property="Background" Value="{StaticResource DefaultControlBackgroundBrush}"/>
<Setter Property="Foreground" Value="{StaticResource DefaultControlForegroundBrush}"/>
<!-- Remove border around the grid -->
<Setter Property="BorderBrush" Value="{x:Null}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="HorizontalGridLinesBrush" Value="{StaticResource GridLineColorBrush}" />
<Setter Property="VerticalGridLinesBrush" Value="{StaticResource GridLineColorBrush}" />
<Setter Property="AlternatingRowBackground" Value="{StaticResource AlternateRowBackgroundBrush}" />
<Setter Property="ColumnHeaderStyle" Value="{StaticResource DataGridColumnHeaderStyle}"/>
<!-- This is needed to force DG to have a non-default value. Otherwise the DGR.DetailsVisibility cannot have a value of VisibleWhenSelected by default. -->
<Setter Property="RowDetailsVisibilityMode" Value="VisibleWhenSelected" />
<Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
<!-- Turn off row headers by default. -->
<Setter Property="HeadersVisibility" Value="Column" />
<Setter Property="GridLinesVisibility" Value="Horizontal" />
<Setter Property="ColumnHeaderHeight" Value="32" />
<Setter Property="RowHeight" Value="32" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGrid}">
<Border
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
SnapsToDevicePixels="True"
Padding="{TemplateBinding Padding}">
<ScrollViewer Focusable="false" Name="DG_ScrollViewer">
<ScrollViewer.Template>
<ControlTemplate TargetType="{x:Type ScrollViewer}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<!--Left Column Header Corner -->
<Button
Command="{x:Static DataGrid.SelectAllCommand}"
Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=CellsPanelHorizontalOffset}"
Focusable="false"
Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=HeadersVisibility, Converter={x:Static DataGrid.HeadersVisibilityConverter}, ConverterParameter={x:Static DataGridHeadersVisibility.All}}"
Template="{StaticResource SelectAllButtonTemplate}"/>
<!--Column Headers-->
<DataGridColumnHeadersPresenter
Grid.Column="1"
Name="PART_ColumnHeadersPresenter"
Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=HeadersVisibility, Converter={x:Static DataGrid.HeadersVisibilityConverter}, ConverterParameter={x:Static DataGridHeadersVisibility.Column}}"/>
<!--DataGrid content-->
<ScrollContentPresenter x:Name="PART_ScrollContentPresenter" Grid.Row="1" Grid.ColumnSpan="2" CanContentScroll="{TemplateBinding CanContentScroll}" />
<ScrollBar
Grid.Row="0" Grid.RowSpan="2" Grid.Column="2" Name="PART_VerticalScrollBar"
Orientation="Vertical"
Maximum="{TemplateBinding ScrollableHeight}"
ViewportSize="{TemplateBinding ViewportHeight}"
Value="{Binding Path=VerticalOffset, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"/>
<Grid Grid.Row="2" Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=NonFrozenColumnsViewportHorizontalOffset}"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ScrollBar
Grid.Column="1"
Name="PART_HorizontalScrollBar"
Orientation="Horizontal"
Maximum="{TemplateBinding ScrollableWidth}"
ViewportSize="{TemplateBinding ViewportWidth}"
Value="{Binding Path=HorizontalOffset, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"/>
</Grid>
</Grid>
</ControlTemplate>
</ScrollViewer.Template>
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsGrouping" Value="true">
<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
</Trigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
The default template for DataGridColumnHeadersPresenter looks something like this:
<ControlTemplate TargetType="{x:Type DataGridColumnHeadersPresenter}">
<Grid>
<DataGridColumnHeader IsHitTestVisible="False"
Name="PART_FillerColumnHeader"/>
<ItemsPresenter />
</Grid>
</ControlTemplate>
The ItemsPresenter will create a DataGridColumnHeader for each column, but the template also includes a single DataGridColumnHeader that stretches across the entire grid to act as a background. It has no content, so it normally just draws the border in the appropriate theme.
However, your DataGridColumnHeader template includes a TextBlock instead of a ContentPresenter, so it will render the DataContext as a string whether or not it is also the content. Try using a ContentPresenter instead of a TextBlock:
<Border BorderBrush="{StaticResource HeaderInnerBorderBrush}"
BorderThickness="0,1,0,0">
<ContentPresenter
Margin="7,0,7,0"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" />
</Border>
I am attempting to create a Tab Control Style that basically looks like buttons at the top that are centered and content panel below that displays the tabitem content.
I have am kind of new to templates but what I have so far works very well except one thing. I want to be able to set the default forground color for text elements. Normally I have accomplished this by using the ContentPresenter with dependency elements. So something like this.
<ContentPresenter TextElement.Foreground="White"/>
This basically makes any TextElement Control written by this Presenter to inherit this property.
Now I am trying to do the same thing but it's not working! I believe it has something to do with my style being wrong.
Style:
<Style x:Key="MainMenuTab" TargetType="{x:Type TabControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<Grid KeyboardNavigation.TabNavigation="Local" Width="{TemplateBinding Width}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Tab Headers Panel -->
<Grid Grid.Row="0" Background="{StaticResource Brush_ApplicationTabBackground}">
<TabPanel
Name="HeaderPanel"
Grid.Row="0"
Panel.ZIndex="1"
HorizontalAlignment="Center"
VerticalAlignment="Center"
IsItemsHost="True"
KeyboardNavigation.TabIndex="1"
Background="{StaticResource Brush_ApplicationTabBackground}"
>
</TabPanel>
</Grid>
<!-- Tab Body -->
<Border
Name="Border"
Grid.Row="1"
Background="{StaticResource Brush_ApplicationBackground}"
BorderBrush="Transparent"
BorderThickness="1"
CornerRadius="2"
KeyboardNavigation.TabNavigation="Local"
KeyboardNavigation.DirectionalNavigation="Contained"
KeyboardNavigation.TabIndex="2" >
<ContentPresenter
Name="PART_SelectedContentHost"
Margin="4"
ContentSource="SelectedContent" />
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<!-- Each Tab should look like this -->
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style>
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid Background="{StaticResource Brush_ApplicationTabBackground}">
<Border Width="50" x:Name="BorderTab" Height="50" Margin="5" BorderThickness="1" ClipToBounds="True" BorderBrush="Transparent" Background="Transparent" CornerRadius="5">
<Rectangle x:Name="BackgroundRec" Fill="Transparent" Stroke="Transparent" Width="50" Height="50" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<ContentPresenter Name="TheHeaderContentPresenter" Width="50" Height="50" Margin="5" ContentSource="Header" HorizontalAlignment="Center" VerticalAlignment="Center" TextElement.Foreground="White"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Trigger.Setters>
<Setter TargetName="BorderTab" Property="BorderBrush" Value="{StaticResource Brush_ApplicationTabHighlight}"/>
<Setter TargetName="BorderTab" Property="BorderThickness" Value="3"/>
<Setter TargetName="BackgroundRec" Property="Fill" Value="{StaticResource Brush_ApplicationTabHighlight}"/>
<Setter Property="Panel.ZIndex" Value="1"/>
</Trigger.Setters>
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Trigger.Setters>
<Setter TargetName="BorderTab" Property="BorderBrush" Value="{StaticResource Brush_ApplicationTabBackground}"/>
<Setter TargetName="BorderTab" Property="BorderThickness" Value="0"/>
<Setter TargetName="BackgroundRec" Property="Fill" Value="{StaticResource Brush_ApplicationTabBackground}"/>
</Trigger.Setters>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
In my ContentPresenter under ItemContainerStyle has the TextElement.Foreground="White" property but it will not print white text!
My tabcontrol that uses this style looks like this:
<TabControl Grid.Row="2" Style="{StaticResource MainMenuTab}">
<TabItem>
<TabItem.Header>
<TextBlock VerticalAlignment="Bottom" HorizontalAlignment="Center" Margin="0,0,0,5" Text="{x:Static UIStrings:ClientStrings.MainWindow_TabHeader_SingleWaveLength}"></TextBlock>
</TabItem.Header>
<TextBlock>TEST PANEL</TextBlock>
</TabItem>
</TabControl>
I know this is compicated but I would really love this to work.
Solution Found.
Based on HCL's post, I have found a solution. I am experiance the same exact problem I am trying to have the content presenter set the inherited dependence property. instead I simple tell the template to apply the dependance property, that way each tabitem is styled to have this property and therefore sets it for all it's children.
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="TabItem">
<Setter Property="TextElement.Foreground" Value="White"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid Background="{StaticResource Brush_ApplicationTabBackground}">
<Border Width="50" x:Name="BorderTab" Height="50" Margin="5" BorderThickness="1" ClipToBounds="True" BorderBrush="Transparent" Background="Transparent" CornerRadius="5">
<Rectangle x:Name="BackgroundRec" Fill="Transparent" Stroke="Transparent" Width="50" Height="50" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<ContentPresenter Name="TheHeaderContentPresenter" Width="50" Height="50" Margin="5" ContentSource="Header" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Trigger.Setters>
<Setter TargetName="BorderTab" Property="BorderBrush" Value="{StaticResource Brush_ApplicationTabHighlight}"/>
<Setter TargetName="BorderTab" Property="BorderThickness" Value="3"/>
<Setter TargetName="BackgroundRec" Property="Fill" Value="{StaticResource Brush_ApplicationTabHighlight}"/>
<Setter Property="Panel.ZIndex" Value="1"/>
</Trigger.Setters>
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Trigger.Setters>
<Setter TargetName="BorderTab" Property="BorderBrush" Value="{StaticResource Brush_ApplicationTabBackground}"/>
<Setter TargetName="BorderTab" Property="BorderThickness" Value="0"/>
<Setter TargetName="BackgroundRec" Property="Fill" Value="{StaticResource Brush_ApplicationTabBackground}"/>
</Trigger.Setters>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
All I've really dont is added the line:
<Setter Property="TextElement.Foreground" Value="White"/>
Before the control template! Also I took the white text out of the content presenter because it is useless.
Check this post, it looks to me as it is the same effect:
ContentPresenter within ControlTemplate cannot change attached dependency property