WPF Visual States & changing colors - wpf

My WPF application needs to have two different color schemes based upon time of day, a day-mode and a night-mode. I'm trying to modify the template used by a third-party WPF control so it will work with the different color schemes.
The control in question uses visual states to define the transition from selected to unselected:
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Calendar:CalendarButton}">
<Grid x:Name="LayoutRoot" Background="Transparent">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="SelectionStates">
<VisualState x:Name="Unselected"/>
<VisualState x:Name="Selected"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}"/>
<Chromes:ButtonChrome x:Name="SelectionChrome" CornerRadius="1" Margin="2" RenderNormal="False" RenderSelected="{TemplateBinding IsSelected}" RenderFocused="{TemplateBinding IsFocused}" RenderHighlighted="{TemplateBinding IsMouseOver}" />
<Border x:Name="TodayVisual" BorderThickness="1" CornerRadius="2" Margin="1" Visibility="Collapsed">
<Border.BorderBrush>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF282828"/>
<GradientStop Color="#FF5F5F5F" Offset="1"/>
</LinearGradientBrush>
</Border.BorderBrush>
</Border>
<ContentPresenter x:Name="Content" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
I need to change the Background, BorderBrush, and Foreground properties of the ButtonChrome control when the visual state is "Selected". How do I do this?

I have found that on most controls that have a Chrome elements (whether they be Microsoft or other parties controls), it is necessary to remove the chrome element, and re-construct it by hand as they often do not provide a method to change them (i.e. no way to substitute a template).
However, if anyone else has a better way, I am all ears.

Related

DisplayMemberPath not working for ListBox with custom ListBoxItem control

I've configured ListBox to use custom ControlTemplate for it self and custom ControlTemplate for ListBoxItem. Unfortunately such change disables the default behvaiour of DisplayMemberPath property.
// resource dictionary of ListBox control template
<ControlTemplate x:Key="CustomListBox" TargetType="ListBox" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:s="clr-namespace:System;assembly=mscorlib">
<Border CornerRadius="3" BorderThickness="{TemplateBinding Border.BorderThickness}" Padding="1,1,1,1" BorderBrush="{TemplateBinding Border.BorderBrush}" Background="{TemplateBinding Panel.Background}" Name="Bd" SnapsToDevicePixels="True">
<ScrollViewer Padding="{TemplateBinding Control.Padding}" Focusable="False">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</ScrollViewer>
</Border>
</ControlTemplate>
//trigger code omitted
<Style TargetType="ListBox">
<Setter Property="Control.Template" Value="{StaticResource CustomListBox}"></Setter>
</Style>
// resource dictionary of ListBoxItem control template
<ControlTemplate x:Key="CustomListBoxItem" TargetType="ListBoxItem" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel>
<Border BorderThickness="0" CornerRadius="3" Padding="6 6" BorderBrush="{TemplateBinding Border.BorderBrush}" Background="White" Name="Bd" SnapsToDevicePixels="True">
<ContentPresenter Content="{TemplateBinding ContentControl.Content}" ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}" ContentStringFormat="{TemplateBinding ContentControl.ContentStringFormat}" HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding Control.VerticalContentAlignment}" SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</Border>
<Label Height="3"></Label>
</StackPanel>
</ControlTemplate>
// trigger code omitted
<Style TargetType="ListBoxItem">
<Setter Property="Control.Template" Value="{StaticResource CustomListBoxItem}"></Setter>
<Setter Property="ItemsControl.DisplayMemberPath" Value="MatchText"></Setter>
</Style>
XAML
<ListBox x:Name="listBox" DisplayMemberPath="MyCustomText">
The DataContext of listBox is set using code. If I omit setting CustomListBoxItem as the control template, than it works as expected. How do you enable DisplayMemberPath when using custom control templates for ListBox and ListBoxItem?

WPF: Why can't I read an attached property from inside a control-template trigger?

In WPF, I created a ControlTemplate for a button, and tried to change the Background Brush through a trigger. To store the value of the brush, I use an attached property.
I tested the attached property itself and it works well - it can be set, and it can be bound to (such as when I simply bind the background to that property).
But when I try to get that property inside the trigger (change the Background to the value of that property), the value isn't even read (as I see when I breakpoint inside the attached property getter), and the background changes to transparent.
How can I fix this?
<ControlTemplate x:Key="DefaultButtonTemplate" TargetType="{x:Type Button}">
<Border
x:Name="border"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="True"
>
<ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" TargetName="border" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ButtonAttachedProperties.BackgroundOnMouseOver}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
It misunderstands you. It thinks you're referencing a property of a property, not a two-part name of one property. Try disambiguating with parens, like this:
Path=(myns:ButtonAttachedProperties.BackgroundOnMouseOver)
Don't forget the namespace.

Sizing the radiobutton

I have some radiobuttons in an app that works with touch.
Because the end-user can have thick fingers, I want to make the circle and text int he radiobutton bigger.
Problem is, I can only make the text bigger, not the circle in the radiobutton.
<RadioButton VerticalAlignment="Center" x:Name="rbtnContainers" Click="SetContainers" FontSize="18">Containers</RadioButton>
Using height doesn't work either. It makes the radiobutton bigger, but the circle remains the same.
Any hint or answer is appreciated.
This should work for you.
<Viewbox Height="40">
<RadioButton></RadioButton>
</Viewbox>
another alternative is to write your own ControlTemplate for the RadioButton and change its appearance as you want.
A more of a hack would be to try to simply transform the object with something like...
<RadioButton.RenderTransform>
<CompositeTransform ScaleX="5" ScaleY="5"/>
</RadioButton.RenderTransform>
Just remember that ScaleX and ScaleY needs to be equal, otherwise the object will look stretched awkwardly
According to my own experimenting, the rendering of this is not at all messed up (e.g. no alignment issues, etc.)
To resize only the circle, one can use RadioButton template and change Width and Height of BulletChrome.
<ControlTemplate TargetType="RadioButton" x:Key="CustomRadioButtonStyle"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mwt="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero">
<BulletDecorator Background="#00FFFFFF">
<BulletDecorator.Bullet>
<mwt:BulletChrome Height="25" Width="25" Background="{TemplateBinding Panel.Background}" BorderBrush="{TemplateBinding Border.BorderBrush}" RenderMouseOver="{TemplateBinding UIElement.IsMouseOver}" RenderPressed="{TemplateBinding ButtonBase.IsPressed}" IsChecked="{TemplateBinding ToggleButton.IsChecked}" IsRound="True" />
</BulletDecorator.Bullet>
<ContentPresenter RecognizesAccessKey="True" Content="{TemplateBinding ContentControl.Content}" ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}" ContentStringFormat="{TemplateBinding ContentControl.ContentStringFormat}" Margin="{TemplateBinding Control.Padding}" HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding Control.VerticalContentAlignment}" />
</BulletDecorator>
<ControlTemplate.Triggers>
<Trigger Property="ContentControl.HasContent">
<Setter Property="FrameworkElement.FocusVisualStyle">
<Setter.Value>
<Style TargetType="IFrameworkInputElement">
<Style.Resources>
<ResourceDictionary />
</Style.Resources>
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2" Margin="14,0,0,0" SnapsToDevicePixels="True" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
<Setter Property="Control.Padding">
<Setter.Value>
<Thickness>4,0,0,0</Thickness>
</Setter.Value>
</Setter>
<Trigger.Value>
<s:Boolean>True</s:Boolean>
</Trigger.Value>
</Trigger>
<Trigger Property="UIElement.IsEnabled">
<Setter Property="TextElement.Foreground">
<Setter.Value>
<DynamicResource ResourceKey="{x:Static SystemColors.GrayTextBrushKey}" />
</Setter.Value>
</Setter>
<Trigger.Value>
<s:Boolean>False</s:Boolean>
</Trigger.Value>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
After hours trying things I finally found a rather simple solution to increase the size of the button, without increasing the associated label.
In the document outline, right-click the radio control, Edit Template > Edit a copy
Give it a name and decide if you want to store it as an App (global) style or local (current window) style.
In the generated xaml code, edit the values minWidth, minHeight of the field Ellipse from the section below
Apply that style to your RadioButton
<Grid x:Name="templateRoot" Background="Transparent" SnapsToDevicePixels="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border x:Name="radioButtonBorder" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="100" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="1,1,2,1" VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
<Grid x:Name="markGrid" Margin="2">
<!-- HERE change minWidth/minHeight for the dimensions of the button -->
<Ellipse x:Name="optionMark" Fill="{StaticResource RadioButton.Static.Glyph}" MinWidth="20" MinHeight="20" Opacity="0"/>
</Grid>
</Border>
<ContentPresenter x:Name="contentPresenter" Grid.Column="1" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Grid>

Different look in design-mode and at runtime

I have small problem with WPF.
Here is my Style where I created a template for DataGrid Column Header.
<Window.Resources>
<Style x:Key="DataGridColumnHeaderStyle1" TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
<Grid>
<Microsoft_Windows_Themes:DataGridHeaderBorder BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" IsClickable="{TemplateBinding CanUserSort}" IsPressed="{TemplateBinding IsPressed}" IsHovered="{TemplateBinding IsMouseOver}" Padding="{TemplateBinding Padding}" SortDirection="{TemplateBinding SortDirection}" SeparatorBrush="{TemplateBinding SeparatorBrush}" SeparatorVisibility="{TemplateBinding SeparatorVisibility}">
<Microsoft_Windows_Themes:DataGridHeaderBorder.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF7EE4FF" Offset="0"/>
<GradientStop Color="#FF66D6F3" Offset="1"/>
<GradientStop Color="#FF0097BE" Offset="0.5"/>
</LinearGradientBrush>
</Microsoft_Windows_Themes:DataGridHeaderBorder.Background>
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Microsoft_Windows_Themes:DataGridHeaderBorder>
</Grid>
</ControlTemplate>
</Setter.Value>
Here's my DataGrid view control in Grid:
<DataGrid Margin="46.667,41.333,102,87">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Status" Width="*" HeaderStyle=" {DynamicResource DataGridColumnHeaderStyle1}"/>
</DataGrid.Columns>
</DataGrid>
The problem is I can see modified header in VS designer, or in Blend, but when I run my application header style is default. Can anyone help? Thanks in advance.
EDIT
Just found interesting thing. When I put Style in
DataGridTemplateColumn.HeaderStyle
it's working
<DataGrid Margin="46.667,41.333,102,87">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Status" Width="*">
<DataGridTemplateColumn.HeaderStyle>
<Style TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
<Grid>
<Microsoft_Windows_Themes:DataGridHeaderBorder BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" IsClickable="{TemplateBinding CanUserSort}" IsPressed="{TemplateBinding IsPressed}" IsHovered="{TemplateBinding IsMouseOver}" Padding="{TemplateBinding Padding}" SortDirection="{TemplateBinding SortDirection}" SeparatorBrush="{TemplateBinding SeparatorBrush}" SeparatorVisibility="{TemplateBinding SeparatorVisibility}">
<Microsoft_Windows_Themes:DataGridHeaderBorder.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF7EE4FF" Offset="0"/>
<GradientStop Color="#FF66D6F3" Offset="1"/>
<GradientStop Color="#FF0097BE" Offset="0.5"/>
</LinearGradientBrush>
</Microsoft_Windows_Themes:DataGridHeaderBorder.Background>
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Microsoft_Windows_Themes:DataGridHeaderBorder>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGridTemplateColumn.HeaderStyle>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
Why does it make a difference?
It looks like the DynamicResource is not resolving correctly at runtime. Try switching your DynamicResource to a StaticResource like so:
<DataGridTemplateColumn Header="Status" Width="*"
HeaderStyle="{StaticResource DataGridColumnHeaderStyle1}"/>
For more details on the differences between DynamicResource and StaticResource, see this other StackOverflow question: What's the difference between StaticResource and DynamicResource in WPF?

How to duplicate the "background" applied to text in Aero window titlebars?

All windows in Aero have this kind of whiteish background on their text. I'd like to create an equivalent of this effect for a GlassWindow I'm using that has a TextBlock in the label area, but I'm not really a designer so I have no idea how to approach this. How can I reproduce this background effect?
This could lead you in the right direction: Glowing Label Controls On A Glass Surface
EDIT: Modified the original sample (linked) and added color tot the blur
<Style TargetType="{x:Type Label}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Label}">
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
Padding="{TemplateBinding Padding}" SnapsToDevicePixels="True">
<Grid>
<ContentPresenter
Content="{TemplateBinding Content}"
ContentStringFormat="{TemplateBinding ContentStringFormat}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
<ContentPresenter.ContentTemplate>
<DataTemplate>
<TextBlock Foreground="White" Text="{TemplateBinding Content}" />
</DataTemplate>
</ContentPresenter.ContentTemplate>
<ContentPresenter.Effect>
<BlurEffect Radius="10" />
</ContentPresenter.Effect>
</ContentPresenter>
<ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Resources