WPF DataGrid Dynamic width cell highlighting - wpf

I have an application that's using the WPF Data Grid. That grid presents a set of test results. If the result of a test is out side the min and max allowed values I want to highlight that cell in red. I currently have it working, but am not quite happy with the highlighting.
Here's what it looks like currently:
Here's the desired look (via some image twiddling):
Notice the highlighting in the first example consumes the entire cell width. I'm hoping for the desired example where it only consumes as much space as the widest result with a little margin on both sides. Keep in mind, a result in any one cell could range between 0 and 1920K from one sample to the next. This is an edge case, but I want the highlighted area to grow and shrink as a result.
Just FYI, these results are updated on a configurable timer that triggers anywhere between 10 ms and 10 seconds depending on the user configuration.
Below is the code that generates the first example (sorry for the large amount of code). The interesting bits are DataGridCellStyle, ResultCellStyle and CellTemplate
The XAML
<Window x:Class="StackOverflow_HighlightCell.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:StackOverflow_HighlightCell"
mc:Ignorable="d"
Loaded="Window_Loaded"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Style TargetType="DataGridColumnHeader">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Foreground" Value="White" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
</Style>
<ControlTemplate x:Key="CellTemplate" TargetType="{x:Type DataGridCell}">
<Border Background="{TemplateBinding Background}">
<ContentPresenter Margin="12,0,0,0" />
</Border>
</ControlTemplate>
<Style x:Key="DataGridCellStyle" TargetType="DataGridCell">
<Setter Property="Background" Value="#707070" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Foreground" Value="#CCCCCC" />
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="ResultCellStyle" TargetType="DataGridCell"
BasedOn="{StaticResource DataGridCellStyle}">
<Setter Property="Template" Value="{StaticResource CellTemplate}" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsResultOutOfBounds,
StringFormat={}{0:0.00}}"
Value="True">
<Setter Property="Background" Value="Red" />
<Setter Property="Foreground" Value="White" />
</DataTrigger>
</Style.Triggers>
</Style>
<Style TargetType="DataGrid" BasedOn="{x:Null}">
<Setter Property="RowBackground" Value="#707070" />
<Setter Property="AutoGenerateColumns" Value="False" />
<Setter Property="IsReadOnly" Value="True" />
<Setter Property="Background" Value="#666666" />
<Setter Property="GridLinesVisibility" Value="None" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="CanUserSortColumns" Value="False" />
<Setter Property="HeadersVisibility" Value="Column" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="Foreground" Value="#CCCCCC" />
<Setter Property="RowDetailsVisibilityMode" Value="Collapsed" />
<Setter Property="CellStyle" Value="{StaticResource DataGridCellStyle}" />
</Style>
<!-- A left justified DataGridTextColumn -->
<Style x:Key="ElementLeftJustified">
<Setter Property="TextBlock.HorizontalAlignment" Value="Left" />
<Setter Property="TextBlock.Margin" Value="15,0,5,0" />
</Style>
<!-- A right justified DataGridTextColumn -->
<Style x:Key="ElementRightJustified">
<Setter Property="TextBlock.HorizontalAlignment" Value="Right" />
<Setter Property="TextBlock.Margin" Value="0,0,5,0" />
</Style>
</Window.Resources>
<Grid Background="#FF666666">
<Border Margin="20" >
<DataGrid x:Name="_testSummaryGrid"
ItemsSource="{Binding TestResults}">
<DataGrid.Columns>
<DataGridTextColumn
MinWidth="75" Header="Test"
Binding="{Binding TestName}"
ElementStyle="{StaticResource ElementLeftJustified}" />
<DataGridTextColumn
MinWidth="75" Header="Min"
Binding="{Binding Min, StringFormat={}{0:0.00}}"
ElementStyle="{StaticResource ElementRightJustified}" />
<DataGridTextColumn
MinWidth="75" Header="Result"
Binding="{Binding Result, StringFormat={}{0:0.00}}"
ElementStyle="{StaticResource ElementRightJustified}"
CellStyle="{StaticResource ResultCellStyle}" />
<DataGridTextColumn
MinWidth="75" Header="Max"
Binding="{Binding Max, StringFormat={}{0:0.00}}"
ElementStyle="{StaticResource ElementRightJustified}" />
</DataGrid.Columns>
</DataGrid>
</Border>
</Grid>
</Window>
The View Model
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Collections.ObjectModel;
namespace StackOverflow_HighlightCell
{
public class ResultsViewModel : ViewModelBase
{
public ResultsViewModel()
{
TestResults = new ObservableCollection<TestResult>
{
{ new TestResult { TestGroup = "Circle",TestName = "Radius",
Min = 100, Max = 153, Result = 150} },
{ new TestResult { TestGroup = "Circle", TestName = "Min Radius",
Min = 0, Max = 90, Result = 97.59 } },
// And so on ...
};
}
public ObservableCollection<TestResult> TestResults { get; set; }
}
public class TestResult : ViewModelBase
{
public string TestGroup { get; set; }
public string TestName { get; set; }
public double Result { get; set; }
public double Min { get; set; }
public double Max { get; set; }
public bool IsResultOutOfBounds { get { return !(Result >= Min && Result <= Max); } }
}
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void FirePropertyChanged(string property)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
}
}

I think this should do what you want:
<ControlTemplate x:Key="ResultCellTemplate" TargetType="{x:Type DataGridCell}">
<Border Background="{TemplateBinding Background}">
<Grid
Margin="12,0,0,0"
HorizontalAlignment="Right"
>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Result" />
</Grid.ColumnDefinitions>
<Border Grid.Column="0" x:Name="ContentPresenterBorder">
<ContentPresenter
/>
</Border>
</Grid>
</Border>
<ControlTemplate.Triggers>
<!--
That stringformat you had will have been ignored because the target
type isn't string.
-->
<DataTrigger Binding="{Binding IsResultOutOfBounds}" Value="True">
<Setter TargetName="ContentPresenterBorder" Property="Background" Value="Red" />
<Setter TargetName="ContentPresenterBorder" Property="TextElement.Foreground" Value="White" />
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<Style x:Key="ResultCellStyle" TargetType="DataGridCell"
BasedOn="{StaticResource DataGridCellStyle}">
<Setter Property="Template" Value="{StaticResource ResultCellTemplate}" />
</Style>
...but don't forget to set Grid.IsSharedSizeScope="True" on the DataGrid. That works with SharedSizeGroup="Result" on the ColumnDefinition to ensure that any grid column named "Result" anywhere within the DataGrid will be dynamically sized to the same width.
<DataGrid
x:Name="_testSummaryGrid"
ItemsSource="{Binding TestResults}"
Grid.IsSharedSizeScope="True"
>
Excellent example by the way. Would've been better trimmed down to just two DataGrid columns, but I pasted it in, pressed F5, and it worked. And the important part wasn't hard to find.

Related

WPF MVVM changing property under controltemplate programmatically

I want to change Border Background programmatically depends on WeekType property. It has All, Even and Odd property. Color of my items are in Border's Background property. So when property is All I want them to stay LightGray, but when All or Even I want to change color of this border
XAML:
<Style TargetType="{x:Type summary:SummaryHourUnitItem}">
<Setter Property="StartTime" Value="{Binding StartTime}" />
<Setter Property="EndTime" Value="{Binding EndTime}" />
<Setter Property="WeekType" Value="{Binding WeekType}" />
<Setter Property="SubGroup" Value="{Binding SubGroup}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type summary:SummaryHourUnitItem}">
<Border Width="Auto" BorderThickness="1,1,1,1" BorderBrush="Black" Background="LightGray"
Margin="0" Padding="3,1.5,0,1.5" >
<ContentPresenter>
<ContentPresenter.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="9" />
<Setter Property="Foreground" Value="Black" />
</Style>
</ContentPresenter.Resources>
</ContentPresenter>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
SummaryHourUnitItem class:
public class SummaryHourUnitItem : ButtonBase
{
public static readonly DependencyProperty StartTimeProperty =
SummaryTimeSlotPanel.StartTimeProperty.AddOwner(typeof(SummaryHourUnitItem));
public static readonly DependencyProperty EndTimeProperty =
SummaryTimeSlotPanel.EndTimeProperty.AddOwner(typeof(SummaryHourUnitItem));
public static readonly DependencyProperty WeekTypeProperty =
SummaryTimeSlotPanel.WeekTypeProperty.AddOwner(typeof(SummaryHourUnitItem));
public static readonly DependencyProperty SubGroupProperty =
SummaryTimeSlotPanel.SubGroupProperty.AddOwner(typeof(SummaryHourUnitItem));
static SummaryHourUnitItem()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(SummaryHourUnitItem),
new FrameworkPropertyMetadata(typeof(SummaryHourUnitItem)));
}
public bool StartTime
{
get => (bool) GetValue(StartTimeProperty);
set => SetValue(StartTimeProperty, value);
}
public bool EndTime
{
get => (bool) GetValue(EndTimeProperty);
set => SetValue(EndTimeProperty, value);
}
public WeekType WeekType
{
get => (WeekType) GetValue(WeekTypeProperty);
set
{
SetValue(WeekTypeProperty, value);
}
}
public SubGroup SubGroup
{
get => (SubGroup)GetValue(SubGroupProperty);
set => SetValue(SubGroupProperty, value);
}
}
How can I achieve that?
You must to use a Style Trigger.
<Border Width="Auto" BorderThickness="1,1,1,1" BorderBrush="Black" Background="LightGray"
Margin="0" Padding="3,1.5,0,1.5" >
<Border.Style>
<Style BasedOn="{StaticResource {x:Type Border}}" TargetType="{x:Type Border}">
<Setter Property="Background" Value="LightGray" />
<Style.Triggers>
<DataTrigger Binding="{Binding WeekType}" Value="XXXX">
<Setter Property="Background" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
<ContentPresenter>
<ContentPresenter.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="9" />
<Setter Property="Foreground" Value="Black" />
</Style>
</ContentPresenter.Resources>
</ContentPresenter>
</Border>
I hope it works for you.

Adding an icon to a cell in a WPF DecExpress grid

I need a fresh set of eyes because I am doing something wrong and can't figure out what. I am trying to add an icon to a DevExpress grid. The icon will be clickable to open the survey for editing. The icon is not displaying.
In the SurveyVMO:
public Image EditIcon { get; set; }
public static List<VMOSurvey> PopulateSurveyList()
{
List<Survey> surveyList = Survey.PopulateSurveyList();
List<VMOSurvey> surveys = new List<VMOSurvey>();
foreach (Survey svy in surveyList)
{
VMOSurvey s = new VMOSurvey(svy);
if (svy.IsEditable)
s.EditIcon = Image.FromFile(#".\Images\pencil.png");
surveys.Add(s);
}
return surveys;
}
Then in the ManageSurveyWindow.xaml:
<Window.Resources>
<Style x:Key="SurveyGrid" TargetType="{x:Type dxg:GridControl}">
<Setter Property="AllowLiveDataShaping" Value="True"/>
<Setter Property="SelectionMode" Value="Row"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="FontSize" Value="18"/>
<Setter Property="FontWeight" Value="Thin"/>
<Setter Property="FontFamily" Value="Helvetica"/>
<Setter Property="Margin" Value="10, 10, 10, 10"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
</Style>
<Style x:Key="ColumnHeaderStyling" TargetType="TextBlock">
<Setter Property="Foreground" Value="White"/>
<Setter Property="FontFamily" Value="Helvetica"/>
<Setter Property="FontWeight" Value="Thin"/>
<Setter Property="FontSize" Value="24"/>
</Style>
<Style x:Key="ManageSurveyTableStyling" TargetType="{x:Type dxg:TableView}">
<Setter Property="ShowFixedTotalSummary" Value="True"/>
<Setter Property="IsTotalSummaryMenuEnabled" Value="False"/>
<Setter Property="ShowGroupedColumns" Value="False" />
<Setter Property="ShowGroupPanel" Value="False"/>
<Setter Property="EnableImmediatePosting" Value="True"/>
<Setter Property="AutoWidth" Value="True"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="VerticalScrollbarVisibility" Value="Auto"/>
</Style>
</Window.Resources>
<Grid>
<dxg:GridControl AllowLiveDataShaping="True" ItemsSource="{Binding Surveys}" >
<dxg:GridControl.Columns>
<dxg:GridColumn x:Name="EditIconColumn">
<dxg:GridColumn.HeaderTemplate>
<DataTemplate>
<TextBlock Text=" " Style="{StaticResource ColumnHeaderStyling}"/>
</DataTemplate>
</dxg:GridColumn.HeaderTemplate>
<dxg:GridColumn.HeaderStyle>
<Style TargetType="Control">
<Setter Property="Background" Value="#52658F"/>
</Style>
</dxg:GridColumn.HeaderStyle>
<DataTemplate>
<Image Height="32" Width="32" Source="{Binding EditIcon}" />
</DataTemplate>
</dxg:GridColumn>
</dxg:GridControl.Columns>
<dxg:GridControl.View>
<dxg:TableView AllowEditing="False" Style="{StaticResource ManageSurveyTableStyling}"/>
</dxg:GridControl.View>
</dxg:GridControl>
</Grid>
I did figure it out. My EditIcon needed to be an ImageSource:
public ImageSource EditIcon { get; set; }
And then I had to add the following code to my xaml file:
<dxg:GridColumn.EditSettings >
<dxe:ImageEditSettings MaxWidth="30">
</dxe:ImageEditSettings>
Now I'm trying to figure out how to add a click event to the image. :)

Unable to bind SelectedItem of ListView when using ControlTemplate to define ListViewItem

I've defined a ListViewItem style as shown below
<Style x:Key="BaseContentStyle" TargetType="{x:Type ListViewItem}">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<ListViewItem Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
FontWeight="{TemplateBinding FontWeight}">
<ContentPresenter/>
</ListViewItem>
<ControlTemplate.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="0">
<Setter Property="Background" Value="#ebebeb"/>
</Trigger>
<DataTrigger Binding="{Binding ListViewPosition}" Value="Conference">
<Setter Property="Content" Value="{Binding Conference}"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="FontWeight" Value="SemiBold"/>
<Setter Property="Background" Value="#192942"/>
</DataTrigger>
<DataTrigger Binding="{Binding ListViewPosition}" Value="Division">
<Setter Property="Content" Value="{Binding Division}"/>
<Setter Property="BorderBrush" Value="LightGray"/>
<Setter Property="BorderThickness" Value="1.5"/>
<Setter Property="FontWeight" Value="SemiBold"/>
<Setter Property="Background" Value="Transparent"/>
</DataTrigger>
<DataTrigger Binding="{Binding ListViewPosition}" Value="Team">
<Setter Property="ContentTemplate" Value="{StaticResource MyDataTemplate}"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I've defined my ListView as follows
<ListView ItemsSource="{Binding AmericanAthleticTeams}"
SelectedItem="{Binding Path=SelectedTeam, Mode=TwoWay}"
ItemContainerStyle="{StaticResource BaseContentStyle}">
This is the DataTemplate used for the ContentTemplate in the Style template
<DataTemplate x:Key="MyDataTemplate" >
<Grid >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="3*"/>
</Grid.ColumnDefinitions>
<Image Source="{Binding Logo, Converter={StaticResource imageConverter}}"
RenderOptions.BitmapScalingMode="Fant"
Grid.Column="0"
Height="15"
Width="15"
HorizontalAlignment="Left"
Margin="5 0 0 0"/>
<TextBlock Text="{Binding Name}"
Grid.Column="1"
HorizontalAlignment="Left"
VerticalAlignment="Center"/>
</Grid>
</DataTemplate>
And here is the ViewModel serving as the View's DataContext
class NCAAFBTeamsViewModel : ViewModelBase
{
public List<NCAAFBTeamViewModel> AmericanAthleticTeams { get; set; }
private NCAAFBTeamViewModel team;
public NCAAFBTeamsViewModel(List<NCAAFBTeamViewModel> americanAthleticTeams)
{
AmericanAthleticTeams = americanAthleticTeams;
}
public NCAAFBTeamViewModel SelectedTeam
{
get { return team; }
set
{
team = value;
OnPropertyChanged();
}
}
}
The problem I'm running into is the binding for the SelectedItem property of the ListView doesn't work as intended. In particular, when I click on one of the displayed ListViewItems, the trigger isn't invoked for the bound SelectedTeam property in the ViewModel. I believe the issue resides with the ControlTemplate of my Style and that perhaps I'm not bubbling up high enough. I've scoured Google and unfortunately wasn't able to discover anything with regards to issues encountered with using a ControlTemplate to define ListViewItems and the impact it has on the SelectedItem property. Any help would be greatly appreciated!

WPF data to bind style

here is my style .xaml:
<Style TargetType="TabItem" x:Key="gMetroTabItem">
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Padding" Value="6,2,6,2" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Stretch" />
<Setter Property="MinWidth" Value="5" />
<Setter Property="MinHeight" Value="5" />
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate DataType="{x:Type local:TabItemHeaderData}">
<StackPanel>
<TextBlock x:Name="rootText" Text="{Binding tabText}" FontSize="26.67"/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
here is my TabItemHeaderData:
public class TabItemHeaderData
{
public String tabText { get; set; }
public object Content { get; set; }
public object tabIconOff { get; set; }
public object tabIconOn { get; set; }
}
my question is: the code of the style seems right, I bind the property tabText to the Text, but how can I send the TabItemHeaderData from my window code? actually is like this:
<TabItem Style="{StaticResource gMetroTabItem}">
<Grid>
...
</Grid>
</TabItem>

wpf tabitem with image

I need to use, with a stile of mahapps.metro, the tabitem with a text and an image..
this is my code:
<TabItem Style="{StaticResource gMetroTabItem}">
<TabItem.Header>
<StackPanel Orientation="Horizontal">
<Image Name="img" Height="auto" Width="auto" Source="/myProject;component/Resources/Black_Tools.png" />
<TextBlock Text="tabItem2" Margin="2,0,0,0" VerticalAlignment="Center" />
</StackPanel>
</TabItem.Header>
</TabItem>
and this is the code of the style:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="{x:Type TabControl}" x:Key="gMetroTabControl">
<Setter Property="Background" Value="{x:Null}" />
<Setter Property="BorderBrush" Value="{x:Null}" />
</Style>
<Style TargetType="TabItem" x:Key="gMetroTabItem">
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Padding" Value="6,2,6,2" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Stretch" />
<Setter Property="MinWidth" Value="5" />
<Setter Property="MinHeight" Value="5" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TabItem">
<Label x:Name="root" FontSize="46.67">
<ContentPresenter ContentSource="Header" RecognizesAccessKey="True" />
</Label>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="root" Property="Foreground">
<Setter.Value>
<SolidColorBrush Color="{DynamicResource AccentColor}" />
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsSelected" Value="false">
<Setter TargetName="root" Property="Foreground">
<Setter.Value>
<SolidColorBrush Color="{DynamicResource GrayNormal}" />
</Setter.Value>
</Setter>
</Trigger>
<Trigger SourceName="root" Property="IsMouseOver" Value="True">
<Setter TargetName="root" Property="Foreground">
<Setter.Value>
<SolidColorBrush Color="Lime" />
</Setter.Value>
</Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<!--<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<AdornerDecorator>
<ContentPresenter Content="{Binding}"/>
</AdornerDecorator>
</DataTemplate>
</Setter.Value>
</Setter>-->
</Style>
</ResourceDictionary>
but doesn't work, 'cause the style go to change a text property, and the image isn't displayed..
any ideas?
From the screencast images you posted:
designtime: http://www.screencast.com/t/TV20zfCi
runtime: http://www.screencast.com/t/7w9rBBEkhMnH
This is indicative of the Black_Tools.png having incorrect properties. Make sure the image is set to be a resource and copied to the output directory:
Right Click Black_Tools.png in the solution explorer > Properties
Build Action: Resource
Copy to Output Directory: Copy always (or Copy if newer)
If the image isn't set as a resource and copied to the output directory, then you'll see the image at design time since the image can be resolved in the solution. However, at runtime, the image path is different since the files will be in the project's output directory.
Scratch what I said before. This is much easier.
You only need the TabControl.ItemTemplate. This is what determines the layout of the header. With some tricky binding to ancestor, you can bind to the TabItem's properties for your DataTriggers.
In this example I show how to bind to the IsSelectedProperty. I'll leave the IsMouseOver as an exercise for you. Hint: Bind to the IsMouseOver using ElementName "root", and then in the setter use TargetName="root".
<Style TargetType="{x:Type TabControl}" x:Key="gMetroTabControl">
<Setter Property="Background" Value="{x:Null}" />
<Setter Property="BorderBrush" Value="{x:Null}" />
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate DataType="{x:Type local:TabItemHeaderData}">
<StackPanel>
<TextBlock Name="root" Text="{Binding LabelText}"/>
<Rectangle Fill="{Binding RectFill}"/>
</StackPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding
RelativeSource={RelativeSource
Mode=FindAncestor,AncestorType={x:Type TabItem}},Path=IsSelected}" Value="true">
<Setter TargetName="root" Property="Foreground">
<Setter.Value>
<SolidColorBrush Color="Blue" />
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding
RelativeSource={RelativeSource
Mode=FindAncestor,AncestorType={x:Type TabItem}},Path=IsSelected}" Value="false">
<Setter TargetName="root" Property="Foreground">
<Setter.Value>
<SolidColorBrush Color="Black" />
</Setter.Value>
</Setter>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate DataType="{x:Type local:TabItemHeaderData}">
<ContentControl Content="{Binding Content}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
Then you'll need to create a dataobject.
public class TabItemHeaderData
{
public Brush RectColor { get; set; }
public String LabelText { get; set; }
public object Content { get; set; }
}
Then you just set the values in the dataobject like so.
<TabControl Style="{StaticResource gMetroTabControl}">
<local:TabItemHeaderData RectColor="Black" LabelText="John">
<local:TabItemHeaderData.Content>
<Button>George</Button>
</local:TabItemHeaderData.Content>
</local:TabItemHeaderData>
<local:TabItemHeaderData RectColor="Black" LabelText="John">
</local:TabItemHeaderData>
</TabControl>

Resources