I want to style the indeterminate state of a WPF checkbox. We have a treeview control with checkboxes, and we want the indeterminate state to represent that some descendants are checked and some are unchecked.
The solution I'm seeing everywhere is to override the default control template for a checkbox and do what I need to do.
I have two problems with that:
I can't find the control template
for a normal Aero checkbox. This
one:
http://msdn.microsoft.com/en-us/library/ms752319.aspx
looks goofy.
The control template I get from Expression Blend has that BulletChrome element in it, and I can't figure out what to do with that.
So does anyone know where to get a checkbox control template that looks "normal" or is there an easier way to just style the indeterminate state by itself?
I'm sure there's an easy way I'm just overlooking... Right?
Try this (modified from the article that publicgk linked to)
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:theme="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero" Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Style x:Key="CheckRadioFocusVisual">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle Margin="14,0,0,0"
StrokeThickness="1"
Stroke="Black"
StrokeDashArray="1 2"
SnapsToDevicePixels="true"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="EmptyCheckBoxFocusVisual">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle Margin="1"
StrokeThickness="1"
Stroke="Black"
StrokeDashArray="1 2"
SnapsToDevicePixels="true"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<SolidColorBrush x:Key="CheckBoxFillNormal"
Color="#F4F4F4"/>
<SolidColorBrush x:Key="CheckBoxStroke"
Color="#8E8F8F"/>
<Style x:Key="{x:Type CheckBox}"
TargetType="{x:Type CheckBox}">
<Setter Property="Foreground"
Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="Background"
Value="{StaticResource CheckBoxFillNormal}"/>
<Setter Property="BorderBrush"
Value="{StaticResource CheckBoxStroke}"/>
<Setter Property="BorderThickness"
Value="1"/>
<Setter Property="FocusVisualStyle"
Value="{StaticResource EmptyCheckBoxFocusVisual}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<BulletDecorator Background="Transparent"
SnapsToDevicePixels="true">
<BulletDecorator.Bullet>
<theme:BulletChrome Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
RenderMouseOver="{TemplateBinding IsMouseOver}"
RenderPressed="{TemplateBinding IsPressed}"
IsChecked="{TemplateBinding IsChecked}"/>
</BulletDecorator.Bullet>
<ContentPresenter Margin="{TemplateBinding Padding}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</BulletDecorator>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked"
Value="{x:Null}">
<!-- TODO: Do Stuff Here -->
</Trigger>
<Trigger Property="HasContent"
Value="true">
<Setter Property="FocusVisualStyle"
Value="{StaticResource CheckRadioFocusVisual}"/>
<Setter Property="Padding"
Value="4,0,0,0"/>
</Trigger>
<Trigger Property="IsEnabled"
Value="false">
<Setter Property="Foreground"
Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<StackPanel>
<CheckBox IsChecked="True" Content="Checked"/>
<CheckBox IsChecked="{x:Null}" Content="Unknown"/>
<CheckBox IsChecked="False" Content="Not Checked"/>
</StackPanel>
</Window>
Have you already tried to download the Aero Theme xaml and looked into it?
Where can I download Microsoft's standard WPF themes from?
You can use CheckBox styling from the classic theme located at:
C:\Program Files (x86)\Microsoft Expression\Blend 4\SystemThemes\Wpf\classic.xaml
This implementation has a Path representing the checkbox mark called CheckMarkPath. I simply replaced this Path with a filled Rectangle to get these results:
Call me crazy, but I've actually reimplemented standard Aero checkbox in pure XAML. If you want to customize Aero checkbox, it's a good starting point. You can find other styles in my repository on GitHub (specific commit, in case files are moved).
BulletCommon.xaml (common resources for CheckBox and RadioButton)
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:xx="clr-namespace:Alba.WpfThemeGenerator.Markup">
<!-- Colors -->
<!-- Background overlay -->
<SolidColorBrush x:Key="Bullet.BackgroundOverlay.Hover" Color="#DEF9FA"/>
<SolidColorBrush x:Key="Bullet.BackgroundOverlay.Pressed" Color="#C2E4F6"/>
<SolidColorBrush x:Key="Bullet.BackgroundOverlay.Disabled" Color="#F4F4F4"/>
<!-- Border overlay -->
<SolidColorBrush x:Key="Bullet.BorderOverlay.Hover" Color="#3C7FB1"/>
<SolidColorBrush x:Key="Bullet.BorderOverlay.Pressed" Color="#2C628B"/>
<SolidColorBrush x:Key="Bullet.BorderOverlay.Disabled" Color="#ADB2B5"/>
<!-- Inner border -->
<LinearGradientBrush x:Key="Bullet.InnerBorder.Disabled" StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="#E1E3E5" Offset="0.25"/>
<GradientStop Color="#E8E9EA" Offset="0.5"/>
<GradientStop Color="#F3F3F3" Offset="1"/>
</LinearGradientBrush>
<!-- Indeterminate inner border -->
<LinearGradientBrush x:Key="Bullet.InnerBorder.IndeterminateDisabled" StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="#BFD0DD" Offset="0"/>
<GradientStop Color="#BDCBD7" Offset="0.5"/>
<GradientStop Color="#BAC4CC" Offset="1"/>
</LinearGradientBrush>
<!-- Inner fill -->
<LinearGradientBrush x:Key="Bullet.InnerFill.Normal" StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="#CBCFD5" Offset="0.2"/>
<GradientStop Color="#F7F7F7" Offset="0.8"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="Bullet.InnerFill.Hover" StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="#B1DFFD" Offset="0.2"/>
<GradientStop Color="#E9F7FE" Offset="0.8"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="Bullet.InnerFill.Pressed" StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="#7FBADC" Offset="0.2"/>
<GradientStop Color="#D6EDF9" Offset="0.8"/>
</LinearGradientBrush>
<!-- Indeterminate fill -->
<LinearGradientBrush x:Key="Bullet.Fill.Indeterminate" StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="#2FA8D5" Offset="0.2"/>
<GradientStop Color="#25598C" Offset="0.8"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="Bullet.Fill.IndeterminateHover" StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="#33D7ED" Offset="0.2"/>
<GradientStop Color="#2094CE" Offset="0.8"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="Bullet.Fill.IndeterminatePressed" StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="#17447A" Offset="0.2"/>
<GradientStop Color="#218BC3" Offset="0.8"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="Bullet.Fill.IndeterminateDisabled" StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="#C0E5F3" Offset="0.2"/>
<GradientStop Color="#BDCDDC" Offset="0.8"/>
</LinearGradientBrush>
<!-- Styles -->
<Style x:Key="Bullet.FocusVisual.Normal">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle Margin="14,0,0,0" SnapsToDevicePixels="True"
StrokeThickness="1" Stroke="{xx:SystemBrush ControlText}" StrokeDashArray="1 2"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="Bullet.FocusVisual.Empty">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle Margin="1" SnapsToDevicePixels="True"
StrokeThickness="1" Stroke="{xx:SystemBrush ControlText}" StrokeDashArray="1 2"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
CheckBox.xaml (resources for CheckBox)
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:xx="clr-namespace:Alba.WpfThemeGenerator.Markup">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="BulletCommon.xaml"/>
</ResourceDictionary.MergedDictionaries>
<!-- Colors -->
<SolidColorBrush x:Key="CheckBox.Stroke" Color="#8E8F8F"/>
<SolidColorBrush x:Key="CheckBox.Fill" Color="#F4F4F4"/>
<!-- Check mark -->
<SolidColorBrush x:Key="CheckBox.Glyph.Stroke.Normal" Color="#FFFFFF"/>
<SolidColorBrush x:Key="CheckBox.Glyph.Stroke.Pressed" Color="#B2FFFFFF"/>
<SolidColorBrush x:Key="CheckBox.Glyph.Fill.Normal" Color="#31347C"/>
<SolidColorBrush x:Key="CheckBox.Glyph.Fill.Pressed" Color="#B231347C"/>
<SolidColorBrush x:Key="CheckBox.Glyph.Fill.Disabled" Color="#AEB7CF"/>
<!-- Inner border -->
<LinearGradientBrush x:Key="CheckBox.InnerBorder" StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="#AEB3B9" Offset="0.25"/>
<GradientStop Color="#C2C4C6" Offset="0.5"/>
<GradientStop Color="#EAEBEB" Offset="1"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="CheckBox.InnerBorder.Hover" StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="#79C6F9" Offset="0.3"/>
<GradientStop Color="#79C6F9" Offset="0.5"/>
<GradientStop Color="#D2EDFD" Offset="1"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="CheckBox.InnerBorder.Pressed" StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="#54A6D5" Offset="0.3"/>
<GradientStop Color="#5EB5E4" Offset="0.5"/>
<GradientStop Color="#C4E5F6" Offset="1"/>
</LinearGradientBrush>
<!-- Indeterminate inner border -->
<LinearGradientBrush x:Key="CheckBox.InnerBorder.Indeterminate" StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="#2A628D" Offset="0"/>
<GradientStop Color="#245479" Offset="0.5"/>
<GradientStop Color="#193B55" Offset="1"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="CheckBox.InnerBorder.IndeterminateHover" StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="#29628D" Offset="0"/>
<GradientStop Color="#245479" Offset="0.5"/>
<GradientStop Color="#193B55" Offset="1"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="CheckBox.InnerBorder.IndeterminatePressed" StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="#193B55" Offset="0"/>
<GradientStop Color="#245479" Offset="0.5"/>
<GradientStop Color="#29628D" Offset="1"/>
</LinearGradientBrush>
<!-- Indeterminate highlight -->
<LinearGradientBrush x:Key="CheckBox.Highlight.Indeterminate" StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="#80FFFFFF" Offset="0"/>
<GradientStop Color="#00FFFFFF" Offset="0.5"/>
<GradientStop Color="#003333A0" Offset="0.5"/>
<GradientStop Color="#003333A0" Offset="1"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="CheckBox.Highlight.IndeterminateHover" StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="#80FFFFFF" Offset="0"/>
<GradientStop Color="#00FFFFFF" Offset="0.5"/>
<GradientStop Color="#003333A0" Offset="0.5"/>
<GradientStop Color="#803333A0" Offset="1"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="CheckBox.Highlight.IndeterminatePressed" StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="#00FFFFFF" Offset="0.5"/>
<GradientStop Color="#20FFFFFF" Offset="1"/>
</LinearGradientBrush>
<!-- Images -->
<PathGeometry x:Key="CheckBox.Glyph.Geometry">
<PathFigure StartPoint="9.0, 1.833" IsClosed="True">
<LineSegment Point="10.667, 3.167"/>
<LineSegment Point="7, 10.667"/>
<LineSegment Point="5.333, 10.667"/>
<LineSegment Point="3.333, 8.167"/>
<LineSegment Point="3.333, 6.833"/>
<LineSegment Point="4.833, 6.5"/>
<LineSegment Point="6, 8"/>
</PathFigure>
</PathGeometry>
<!-- Styles -->
<Style x:Key="{x:Type CheckBox}" TargetType="{x:Type CheckBox}">
<Setter Property="FocusVisualStyle" Value="{StaticResource Bullet.FocusVisual.Empty}"/>
<Setter Property="Foreground" Value="{xx:SystemBrush ControlText}"/>
<Setter Property="Background" Value="{StaticResource CheckBox.Fill}"/>
<Setter Property="BorderBrush" Value="{StaticResource CheckBox.Stroke}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<BulletDecorator Background="Transparent" SnapsToDevicePixels="True">
<BulletDecorator.Bullet>
<Grid Width="13" Height="13">
<Rectangle x:Name="Background" Margin="0" Fill="{TemplateBinding Background}"/>
<Rectangle x:Name="BackgroundOverlay" Margin="0"/>
<Rectangle x:Name="InnerFill" Margin="3" Fill="{StaticResource Bullet.InnerFill.Normal}"/>
<Rectangle x:Name="InnerBorder" Margin="2" Stroke="{StaticResource CheckBox.InnerBorder}"/>
<Rectangle x:Name="Highlight" Margin="3"/>
<Path x:Name="GlyphStroke" Margin="0" StrokeThickness="1.5" Data="{StaticResource CheckBox.Glyph.Geometry}"/>
<Path x:Name="GlyphFill" Margin="0" Data="{StaticResource CheckBox.Glyph.Geometry}"/>
<Rectangle x:Name="Border" Margin="0" Stroke="{TemplateBinding BorderBrush}"/>
<Rectangle x:Name="BorderOverlay" Margin="0"/>
</Grid>
</BulletDecorator.Bullet>
<ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" Margin="{TemplateBinding Padding}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
RecognizesAccessKey="True"/>
</BulletDecorator>
<ControlTemplate.Triggers>
<Trigger Property="HasContent" Value="True">
<!-- if (HasContent) -->
<Setter Property="FocusVisualStyle" Value="{StaticResource Bullet.FocusVisual.Normal}"/>
<Setter Property="Padding" Value="4,0,0,0"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<!-- if (IsMouseOver) -->
<Setter TargetName="BackgroundOverlay" Property="Fill" Value="{StaticResource Bullet.BackgroundOverlay.Hover}"/>
<Setter TargetName="InnerFill" Property="Fill" Value="{StaticResource Bullet.InnerFill.Hover}"/>
<Setter TargetName="BorderOverlay" Property="Stroke" Value="{StaticResource Bullet.BorderOverlay.Hover}"/>
<Setter TargetName="InnerBorder" Property="Stroke" Value="{StaticResource CheckBox.InnerBorder.Hover}"/>
</Trigger>
<Trigger Property="IsChecked" Value="{x:Null}">
<!-- if (IsChecked == null) -->
<Setter TargetName="Highlight" Property="Stroke" Value="{StaticResource CheckBox.Highlight.Indeterminate}"/>
<Setter TargetName="InnerFill" Property="Fill" Value="{StaticResource Bullet.Fill.Indeterminate}"/>
<Setter TargetName="InnerBorder" Property="Stroke" Value="{StaticResource CheckBox.InnerBorder.Indeterminate}"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<!-- if (IsPressed) -->
<Setter TargetName="BackgroundOverlay" Property="Fill" Value="{StaticResource Bullet.BackgroundOverlay.Pressed}"/>
<Setter TargetName="InnerFill" Property="Fill" Value="{StaticResource Bullet.InnerFill.Pressed}"/>
<Setter TargetName="BorderOverlay" Property="Stroke" Value="{StaticResource Bullet.BorderOverlay.Pressed}"/>
<Setter TargetName="InnerBorder" Property="Stroke" Value="{StaticResource CheckBox.InnerBorder.Pressed}"/>
</Trigger>
<MultiTrigger>
<!-- if (IsChecked == null && IsMouseOver) -->
<MultiTrigger.Conditions>
<Condition Property="IsChecked" Value="{x:Null}"/>
<Condition Property="IsMouseOver" Value="True"/>
</MultiTrigger.Conditions>
<Setter TargetName="Highlight" Property="Stroke" Value="{StaticResource CheckBox.Highlight.IndeterminateHover}"/>
<Setter TargetName="InnerFill" Property="Fill" Value="{StaticResource Bullet.Fill.IndeterminateHover}"/>
<Setter TargetName="InnerBorder" Property="Stroke" Value="{StaticResource CheckBox.InnerBorder.IndeterminateHover}"/>
</MultiTrigger>
<MultiTrigger>
<!-- if (IsChecked == null && IsPressed) -->
<MultiTrigger.Conditions>
<Condition Property="IsChecked" Value="{x:Null}"/>
<Condition Property="IsPressed" Value="True"/>
</MultiTrigger.Conditions>
<Setter TargetName="Highlight" Property="Stroke" Value="{StaticResource CheckBox.Highlight.IndeterminatePressed}"/>
<Setter TargetName="InnerFill" Property="Fill" Value="{StaticResource Bullet.Fill.IndeterminatePressed}"/>
<Setter TargetName="InnerBorder" Property="Stroke" Value="{StaticResource CheckBox.InnerBorder.IndeterminatePressed}"/>
</MultiTrigger>
<MultiTrigger>
<!-- if (IsChecked == true && IsPressed) -->
<MultiTrigger.Conditions>
<Condition Property="IsChecked" Value="True"/>
<Condition Property="IsPressed" Value="True"/>
</MultiTrigger.Conditions>
<Setter TargetName="GlyphStroke" Property="Stroke" Value="{StaticResource CheckBox.Glyph.Stroke.Pressed}"/>
<Setter TargetName="GlyphFill" Property="Fill" Value="{StaticResource CheckBox.Glyph.Fill.Pressed}"/>
</MultiTrigger>
<MultiTrigger>
<!-- if (IsChecked == true && !IsPressed) -->
<MultiTrigger.Conditions>
<Condition Property="IsChecked" Value="True"/>
<Condition Property="IsPressed" Value="False"/>
</MultiTrigger.Conditions>
<Setter TargetName="GlyphStroke" Property="Stroke" Value="{StaticResource CheckBox.Glyph.Stroke.Normal}"/>
<Setter TargetName="GlyphFill" Property="Fill" Value="{StaticResource CheckBox.Glyph.Fill.Normal}"/>
</MultiTrigger>
<Trigger Property="IsEnabled" Value="False">
<!-- if (!IsEnabled) -->
<Setter Property="Foreground" Value="{xx:SystemBrush GrayText}"/>
<Setter TargetName="InnerFill" Property="Fill" Value="{x:Null}"/>
<Setter TargetName="GlyphStroke" Property="Stroke" Value="{x:Null}"/>
<Setter TargetName="BorderOverlay" Property="Stroke" Value="{StaticResource Bullet.BorderOverlay.Disabled}"/>
<Setter TargetName="InnerBorder" Property="Stroke" Value="{StaticResource Bullet.InnerBorder.Disabled}"/>
</Trigger>
<MultiTrigger>
<!-- if (IsChecked == null && !IsEnabled) -->
<MultiTrigger.Conditions>
<Condition Property="IsChecked" Value="{x:Null}"/>
<Condition Property="IsEnabled" Value="False"/>
</MultiTrigger.Conditions>
<Setter TargetName="InnerFill" Property="Fill" Value="{StaticResource Bullet.Fill.IndeterminateDisabled}"/>
<Setter TargetName="InnerBorder" Property="Stroke" Value="{StaticResource Bullet.InnerBorder.IndeterminateDisabled}"/>
</MultiTrigger>
<MultiTrigger>
<!-- if (IsChecked == true && !IsEnabled) -->
<MultiTrigger.Conditions>
<Condition Property="IsChecked" Value="True"/>
<Condition Property="IsEnabled" Value="False"/>
</MultiTrigger.Conditions>
<Setter TargetName="GlyphFill" Property="Fill" Value="{StaticResource CheckBox.Glyph.Fill.Disabled}"/>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Notes:
{xx:SystemBrush ControlText} is a shortcut for {DynamicResource {x:Static SystemColors.ControlTextBrushKey}}. You can either use that shortcut or just find and replace with regex.
RTL, animations, weird cases are not supported.
This style is slower than using BulletChrome which is heavily optimized.
The below code is a sample check box with three state.
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<!-- Focus Style -->
<SolidColorBrush x:Key="InputBackgroundFocused" Color="Orange"></SolidColorBrush>
<Style x:Key="CheckBoxFocusVisualStyle">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Border CornerRadius="2" Margin="0,0,4,3" BorderThickness="2" BorderBrush="{StaticResource InputBackgroundFocused}" Background="Transparent"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Fill Brushes -->
<LinearGradientBrush x:Key="NormalBrush" StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#FFF" Offset="0.0"/>
<GradientStop Color="#CCC" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="HorizontalNormalBrush" StartPoint="0,0" EndPoint="1,0">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#FFF" Offset="0.0"/>
<GradientStop Color="#CCC" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="LightBrush" StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#FFF" Offset="0.0"/>
<GradientStop Color="#EEE" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="HorizontalLightBrush" StartPoint="0,0" EndPoint="1,0">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#FFF" Offset="0.0"/>
<GradientStop Color="#EEE" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="DarkBrush" StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#FFF" Offset="0.0"/>
<GradientStop Color="#AAA" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="PressedBrush" StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#BBB" Offset="0.0"/>
<GradientStop Color="#EEE" Offset="0.1"/>
<GradientStop Color="#EEE" Offset="0.9"/>
<GradientStop Color="#FFF" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<SolidColorBrush x:Key="DisabledForegroundBrush" Color="#888" />
<SolidColorBrush x:Key="DisabledBackgroundBrush" Color="#EEE" />
<SolidColorBrush x:Key="WindowBackgroundBrush" Color="#FFF" />
<SolidColorBrush x:Key="SelectedBackgroundBrush" Color="#DDD" />
<!-- Border Brushes -->
<LinearGradientBrush x:Key="NormalBorderBrush" StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#CCC" Offset="0.0"/>
<GradientStop Color="#444" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="HorizontalNormalBorderBrush" StartPoint="0,0" EndPoint="1,0">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#CCC" Offset="0.0"/>
<GradientStop Color="#444" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="DefaultedBorderBrush" StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#777" Offset="0.0"/>
<GradientStop Color="#000" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="PressedBorderBrush" StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#444" Offset="0.0"/>
<GradientStop Color="#888" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<SolidColorBrush x:Key="DisabledBorderBrush" Color="#AAA" />
<SolidColorBrush x:Key="SolidBorderBrush" Color="#888" />
<SolidColorBrush x:Key="LightBorderBrush" Color="#AAA" />
<!-- Miscellaneous Brushes -->
<SolidColorBrush x:Key="GlyphBrush" Color="#444" />
<SolidColorBrush x:Key="LightColorBrush" Color="#DDD" />
<Style TargetType="{x:Type CheckBox}">
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="FocusVisualStyle" Value="{DynamicResource CheckBoxFocusVisualStyle}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="CheckBox">
<BulletDecorator Background="Transparent">
<BulletDecorator.Bullet>
<Border x:Name="Border"
Width="17"
Height="17"
CornerRadius="2"
Background="{StaticResource NormalBrush}"
BorderThickness="1"
BorderBrush="{StaticResource NormalBorderBrush}">
<Path
Width="11" Height="11"
x:Name="CheckMark"
SnapsToDevicePixels="False"
Stroke="{StaticResource GlyphBrush}"
StrokeThickness="2"
Data="M 2,4 C 2,4 3,5 5,13 C 5,13 5,3 12,0" />
</Border>
</BulletDecorator.Bullet>
<ContentPresenter Margin="4,0,0,0"
VerticalAlignment="Center"
HorizontalAlignment="Left"
RecognizesAccessKey="True"/>
</BulletDecorator>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="false">
<Setter TargetName="CheckMark" Property="Visibility" Value="Collapsed"/>
</Trigger>
<Trigger Property="IsChecked" Value="{x:Null}">
<Setter TargetName="CheckMark" Property="Data" Value="M 0 7 L 7 0" />
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="Border" Property="Background" Value="{StaticResource DarkBrush}" />
</Trigger>
<Trigger Property="IsPressed" Value="true">
<Setter TargetName="Border" Property="Background" Value="{StaticResource PressedBrush}" />
<Setter TargetName="Border" Property="BorderBrush" Value="{StaticResource PressedBorderBrush}" />
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter TargetName="Border" Property="Background" Value="{StaticResource DisabledBackgroundBrush}" />
<Setter TargetName="Border" Property="BorderBrush" Value="{StaticResource DisabledBorderBrush}" />
<Setter Property="Foreground" Value="{StaticResource DisabledForegroundBrush}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<StackPanel>
<CheckBox>Hello</CheckBox>
<CheckBox IsThreeState="True">asdfsdaf</CheckBox>
</StackPanel>
</Grid>
The best software to modify the existing look and feel of the controls is Expression Blend. If you want to change the existing look and feel and you have to modify the Control Template of the control.
Another option may be to style a toggle button as it has multiple states as well. In past projects I have created custom toggle buttons with multiple states that look and function as chekcboxes. I did use blend to make the changes but in using a tggle button as the base I was able to create a more customized look and feel for the various states of the button/chekcbox. Using a toggle button can bypass a lot of the chrome related issues that are tightly boud to a standard chekcbox control.
Have you thought about using SimpleStyles as the base for control?
By selecting this control from the Assets panel, Expression Blend will place a new resource dictonary in your project that you can use to modify the style as you please. Might be a better starting point than trying to hack into the Chrome for the standard checkbox.
Using the template from Blend:
To make BulletChrome work, you need to add a reference to PresentationFramework.Aero, and add the xml namespace declaration for the "theme" namespace:
xmlns:theme="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"
I didn't try this myself but I believe it should work (I've done it with Luna).
You can set the checkbox's IsThreeState property to true.
This, however, allows toggling the checkbox's value to null.
If that is undesired, you can instead add to your CheckBox's Template a trigger for the null value, just like Greg Bacchus shows in his answer:
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="{x:Null}">
<!-- TODO: Do Stuff Here -->
</Trigger>
</ControlTemplate.Triggers>
Related
Trigger is not working. IsMouseOver is not changing style of the Button. I am not sure what is wrong with my code. I am trying to change the style property of the button on mouse over property. It keeps throwing error.
Basically I am trying to use different style on mouse over event
<Style x:Key="FancyButtonStyle" TargetType="{x:Type Button}">
<Setter Property="FontSize" Value="{Binding FontSize}"/>
<Setter Property="Foreground" Value="{Binding Foreground}"/>
<Setter Property="FontWeight" Value="{Binding FontWeight}"/>
<Setter Property="Width" Value="{Binding Width}"/>
<Setter Property="Height" Value="{Binding Height}"/>
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="0.0" Color="White" />
<GradientStop Offset="0.2" Color="DarkGray" />
<GradientStop Offset="0.6" Color="Black" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Style" Value="{StaticResource ResourceKey=FancyButtonInvertStyle}"/>
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="FancyButtonInvertStyle" TargetType="{x:Type Button}">
<Setter Property="FontSize" Value="{Binding FontSize}"/>
<Setter Property="Foreground" Value="{Binding Foreground}"/>
<Setter Property="FontWeight" Value="{Binding FontWeight}"/>
<Setter Property="Width" Value="{Binding Width}"/>
<Setter Property="Height" Value="{Binding Height}"/>
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="0.0" Color="Black" />
<GradientStop Offset="0.4" Color="DarkGray" />
<GradientStop Offset="0.6" Color="White" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Style>
Instead of trying to change the Style in the Trigger, change the Background directly in it. Keeps you also from repeating the Style completely over again.
<Style x:Key="FancyButtonStyle" TargetType="{x:Type Button}">
<Setter Property="FontSize" Value="{Binding FontSize}"/>
<Setter Property="Foreground" Value="{Binding Foreground}"/>
<Setter Property="FontWeight" Value="{Binding FontWeight}"/>
<Setter Property="Width" Value="{Binding Width}"/>
<Setter Property="Height" Value="{Binding Height}"/>
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="0.0" Color="White" />
<GradientStop Offset="0.2" Color="DarkGray" />
<GradientStop Offset="0.6" Color="Black" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="0.0" Color="Black" />
<GradientStop Offset="0.4" Color="DarkGray" />
<GradientStop Offset="0.6" Color="White" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
I'm not sure if you even can change the Style of itself in the Trigger the way you intend to, because it is not set via a Setter Tag in the target control itself.
I am new to using WPF and I was trying to apply Style (e.g. Background for TextBox, Button and MenuItem should be Orange). To achieve this I did something like:
<Style TargetType="TextBox" x:Key="sampleTextBox">
<Setter Property="Margin" Value="2"/>
<Setter Property="FontFamily" Value="Verdana"/>
<Setter Property="FontSize" Value="11px"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1" >
<GradientStop Color="#FFFFD190" Offset="0.2"/>
<GradientStop Color="Orange" Offset="0.85"/>
<GradientStop Color="#FFFFD190" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Style>
and repeated the same piece of code for targettype Button and for target menu.
This is working absolutely fine. But I would like to minimize the amount of repeated code by probably having multiple targettype values.
Please let me know if it is possible.
Thanks.
<Window.Resources>
<Style x:Key="sampleTextBox">
<Setter Property="Control.FontFamily" Value="Verdana"/>
<Setter Property="Control.FontSize" Value="11px"/>
<Setter Property="Control.FontWeight" Value="Bold"/>
<Setter Property="Control.Background">
<Setter.Value>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1" >
<GradientStop Color="#FFFFD190" Offset="0.2"/>
<GradientStop Color="Orange" Offset="0.85"/>
<GradientStop Color="#FFFFD190" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<StackPanel>
<TextBlock Text="This is a string and it should be wrapped." Style="{StaticResource sampleTextBox}"/>
<TextBox Text="This is a string and it should be wrapped." Style="{StaticResource sampleTextBox}"/>
</StackPanel>
Style has an attribute BasedOn. http://msdn.microsoft.com/en-us/library/system.windows.style.basedon.aspx With this you can use Style inheritance. Define a base style with common attributes and derive your child styles with specific attributes.
You could use FrameworkElement as a TargetType:
<Style TargetType="FrameworkElement" x:Key="CommonStyle">
<Setter Property="Control.Background">
<Setter.Value>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1" >
<GradientStop Color="#FFFFD190" Offset="0.2"/>
<GradientStop Color="Orange" Offset="0.85"/>
<GradientStop Color="#FFFFD190" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Style>
And then use specific styles for each element by inheriting (BasedOn) CommonStyle:
<Style TergetType="TextBox" BasedOn="{StaticResource CommonStyle}" x:Key="TextBoxStyle">
<Setter Property="Margin" Value="2"/>
<Setter Property="FontFamily" Value="Verdana"/>
<Setter Property="FontSize" Value="11px"/>
<Setter Property="FontWeight" Value="Bold"/>
</Style>
As explained in the following article http://vbcity.com/blogs/xtab/archive/2009/12/15/wpf-using-a-virtualizingstackpanel-to-improve-combobox-performance.aspx, I use the VirtualizingStackPanel to improve the performance of my project's ComboBoxes.
And it works great ... until I apply a style to ComboBox to change the layout (I found the style here : http://msdn.microsoft.com/en-us/library/ee230084.aspx)
Here is the source code of a sample which demonstrate the matter (figuring that ItemSource propery of the ComboBox are filled with 10 000 items).
If anyone has an idea ...
<Window.Resources>
<!-- Fill Brushes -->
<LinearGradientBrush x:Key="NormalBrush" StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#FFF" Offset="0.0"/>
<GradientStop Color="#CCC" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="HorizontalNormalBrush" StartPoint="0,0" EndPoint="1,0">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#FFF" Offset="0.0"/>
<GradientStop Color="#CCC" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="LightBrush" StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#FFF" Offset="0.0"/>
<GradientStop Color="#EEE" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="HorizontalLightBrush" StartPoint="0,0" EndPoint="1,0">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#FFF" Offset="0.0"/>
<GradientStop Color="#EEE" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="DarkBrush" StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#FFF" Offset="0.0"/>
<GradientStop Color="#AAA" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="PressedBrush" StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#BBB" Offset="0.0"/>
<GradientStop Color="#EEE" Offset="0.1"/>
<GradientStop Color="#EEE" Offset="0.9"/>
<GradientStop Color="#FFF" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<SolidColorBrush x:Key="DisabledForegroundBrush" Color="Black" />
<SolidColorBrush x:Key="DisabledBackgroundBrush" Color="#E5E5E5" />
<SolidColorBrush x:Key="WindowBackgroundBrush" Color="#FFF" />
<SolidColorBrush x:Key="SelectedBackgroundBrush" Color="#DDD" />
<!-- Border Brushes -->
<LinearGradientBrush x:Key="NormalBorderBrush" StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#AAA" Offset="0.0"/>
<GradientStop Color="#AAA" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="HorizontalNormalBorderBrush" StartPoint="0,0" EndPoint="1,0">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#AAA" Offset="0.0"/>
<GradientStop Color="#AAA" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="DefaultedBorderBrush" StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#AAA" Offset="0.0"/>
<GradientStop Color="#AAA" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="PressedBorderBrush" StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#AAA" Offset="0.0"/>
<GradientStop Color="#AAA" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<SolidColorBrush x:Key="DisabledBorderBrush" Color="#AAA" />
<SolidColorBrush x:Key="SolidBorderBrush" Color="#888" />
<SolidColorBrush x:Key="LightBorderBrush" Color="#AAA" />
<!-- Miscellaneous Brushes -->
<SolidColorBrush x:Key="GlyphBrush" Color="#444" />
<SolidColorBrush x:Key="LightColorBrush" Color="#DDD" />
<ControlTemplate x:Key="ComboBoxToggleButton" TargetType="ToggleButton">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="16" />
</Grid.ColumnDefinitions>
<Border x:Name="Border" Grid.ColumnSpan="2" CornerRadius="2" Background="{StaticResource NormalBrush}" BorderBrush="{StaticResource NormalBorderBrush}" BorderThickness="1" />
<Border x:Name="Border2" Grid.Column="0" CornerRadius="2,0,0,2" Margin="1" Background="{StaticResource WindowBackgroundBrush}" BorderBrush="{StaticResource NormalBorderBrush}" BorderThickness="0,0,1,0" />
<Path x:Name="Arrow" Grid.Column="1" Fill="{StaticResource GlyphBrush}" HorizontalAlignment="Center" VerticalAlignment="Center" Data="M 0 0 L 4 4 L 8 0 Z"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="ToggleButton.IsMouseOver" Value="true">
<Setter TargetName="Border" Property="Background" Value="{StaticResource DarkBrush}" />
</Trigger>
<Trigger Property="ToggleButton.IsChecked" Value="true">
<Setter TargetName="Border" Property="Background" Value="{StaticResource PressedBrush}" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="Border" Property="Background" Value="{StaticResource DisabledBackgroundBrush}" />
<Setter TargetName="Border" Property="BorderBrush" Value="{StaticResource DisabledBorderBrush}" />
<Setter TargetName="Border2" Property="Background" Value="{StaticResource DisabledBackgroundBrush}" />
<Setter TargetName="Border2" Property="BorderBrush" Value="{StaticResource DisabledBorderBrush}" />
<Setter Property="Foreground" Value="{StaticResource DisabledForegroundBrush}"/>
<Setter TargetName="Arrow" Property="Fill" Value="{StaticResource DisabledForegroundBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<ControlTemplate x:Key="ComboBoxTextBox" TargetType="TextBox">
<Border x:Name="PART_ContentHost" Focusable="False" Background="{TemplateBinding Background}" />
</ControlTemplate>
<Style x:Key="ComboBoxBaseStyle" TargetType="ComboBox">
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
<Setter Property="MinHeight" Value="20"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBox">
<Grid>
<ToggleButton Name="ToggleButton" Template="{StaticResource ComboBoxToggleButton}" Grid.Column="2" Focusable="false" IsChecked="{Binding Path=IsDropDownOpen,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}" ClickMode="Press">
</ToggleButton>
<ContentPresenter Name="ContentSite" IsHitTestVisible="False" Content="{TemplateBinding SelectionBoxItem}" ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}" ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}" Margin="3,3,23,3" VerticalAlignment="Center" HorizontalAlignment="Left" />
<TextBox x:Name="PART_EditableTextBox" Style="{x:Null}" Template="{StaticResource ComboBoxTextBox}" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="3,3,23,3" Focusable="True" Background="Transparent" Visibility="Hidden" IsReadOnly="{TemplateBinding IsReadOnly}"/>
<Popup Name="Popup" Placement="Bottom" IsOpen="{TemplateBinding IsDropDownOpen}" AllowsTransparency="True" Focusable="False" PopupAnimation="Slide">
<Grid Name="DropDown" SnapsToDevicePixels="True" MinWidth="{TemplateBinding ActualWidth}" MaxHeight="{TemplateBinding MaxDropDownHeight}">
<Border x:Name="DropDownBorder" Background="{StaticResource WindowBackgroundBrush}" BorderThickness="1" BorderBrush="{StaticResource SolidBorderBrush}"/>
<ScrollViewer Margin="4,6,4,6" SnapsToDevicePixels="True">
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
</ScrollViewer>
</Grid>
</Popup>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="HasItems" Value="false">
<Setter TargetName="DropDownBorder" Property="MinHeight" Value="95"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{StaticResource DisabledForegroundBrush}"/>
</Trigger>
<Trigger Property="IsGrouping" Value="true">
<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
</Trigger>
<Trigger SourceName="Popup" Property="Popup.AllowsTransparency" Value="true">
<Setter TargetName="DropDownBorder" Property="CornerRadius" Value="4"/>
<Setter TargetName="DropDownBorder" Property="Margin" Value="0,2,0,0"/>
</Trigger>
<Trigger Property="IsEditable" Value="true">
<Setter Property="IsTabStop" Value="false"/>
<Setter TargetName="PART_EditableTextBox" Property="Visibility" Value="Visible"/>
<Setter TargetName="ContentSite" Property="Visibility" Value="Hidden"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel>
<ComboBox x:Name="CustomerComboBox_WithoutStyle" SelectedValuePath="Id" DisplayMemberPath="Text" >
<ComboBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ComboBox.ItemsPanel>
</ComboBox>
<ComboBox x:Name="CustomerComboBox_WithStyle" SelectedValuePath="Id" DisplayMemberPath="Text" Style="{StaticResource ComboBoxBaseStyle}" >
<ComboBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ComboBox.ItemsPanel>
</ComboBox>
</StackPanel>
The problem of your style is that it does not use any kind of UI Virtualization.
Try replacing the StackPanel with a VirtualizingStackpanel and set the VirtualizationMode to Recycle and you will see a huge performance boost.
Your approach forces WPF to realize a container and FrameworkElement for each of your 10k items, which takes an eternity as you have only 1 UI thread.
Just replace
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
with
<VirtualizingStackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
and see if it gets faster.
To be more precise, you override the ItemsPanel in your derived styles, but have no "ItemsPresenter" in the base style. Instead to use the StackPanel "hardcoded"
So many items probably is the result of a (UI) design flaw.
Try using a listbox or multiple combo boxes where the first combo box is a category and second is a sub category of the first.
having 10000 items in a combox is not very good design. MaxDropDownItems might be able to help you as less rendering is required. (this is the number of visible items shown when clicking the dropdown)
But, you should consider using a listbox. When you apply a listbox you should uses pages and on each page have 1000 records. Or use a search box
I've seen the following thread which is related to my question:
WPF ComboBox: background color when disabled
The above deals with changing the Content Template for a ComboBox. I am working with WPF, am somewhat new to Styles and Templates, and I want to change the dull gray background color of a disabled TextBox to some other color. We use TextBoxes frequently in our application and we find the default color settings difficult to read.
I've crafted the following solution attempt. But of course, it does not work. Can someone give me an opinion on why?
Unfortunately for the TextBox control, it appears like it's not as simple as just adding a trigger and changing the Background color when the trigger condition is true. You have to override the entire ControlTemplate to achieve this. Below is one example on how you might do this:
<Window x:Class="StackOverflow.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<SolidColorBrush x:Key="DisabledForegroundBrush" Color="Red" />
<SolidColorBrush x:Key="DisabledBackgroundBrush" Color="White" />
<Style TargetType="TextBox">
<Setter Property="Background" Value="White"/>
<Setter Property="BorderBrush" Value="Black"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<Border Name="Bd" BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="true">
<ScrollViewer Name="PART_ContentHost" Background="{TemplateBinding Background}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Value="{StaticResource DisabledBackgroundBrush}" Property="Background" />
<Setter Value="{StaticResource DisabledForegroundBrush}" Property="Foreground" />
<Setter TargetName="PART_ContentHost" Property="Background" Value="Blue"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Canvas>
<TextBox Text="TextBox" IsEnabled="False"/>
<TextBox Text="TextBox" IsEnabled="True" Canvas.Top="25"/>
</Canvas>
</Window>
EDIT:
In response to your question, I tried adding the ComboBox style to my original answer above and I was able to integrate it without errors. I'm not sure though if it behaves like you wanted it to. I just copy-pasted what's in the link you specified.
<Window x:Class="StackOverflow.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:StackOverflow"
Title="MainWindow" Height="350" Width="525"
x:Name="window">
<Window.Resources>
<SolidColorBrush x:Key="DisabledForegroundBrush" Color="Red" />
<SolidColorBrush x:Key="DisabledBackgroundBrush" Color="Blue" />
<LinearGradientBrush x:Key="NormalBrush" StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#FFF" Offset="0.0"/>
<GradientStop Color="#CCC" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="HorizontalNormalBrush" StartPoint="0,0" EndPoint="1,0">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#FFF" Offset="0.0"/>
<GradientStop Color="#CCC" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="LightBrush" StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#FFF" Offset="0.0"/>
<GradientStop Color="#EEE" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="HorizontalLightBrush" StartPoint="0,0" EndPoint="1,0">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#FFF" Offset="0.0"/>
<GradientStop Color="#EEE" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="DarkBrush" StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#FFF" Offset="0.0"/>
<GradientStop Color="#AAA" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="PressedBrush" StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#BBB" Offset="0.0"/>
<GradientStop Color="#EEE" Offset="0.1"/>
<GradientStop Color="#EEE" Offset="0.9"/>
<GradientStop Color="#FFF" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<SolidColorBrush x:Key="WindowBackgroundBrush" Color="#FFF" />
<SolidColorBrush x:Key="SelectedBackgroundBrush" Color="#DDD" />
<!-- Border Brushes -->
<LinearGradientBrush x:Key="NormalBorderBrush" StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#CCC" Offset="0.0"/>
<GradientStop Color="#444" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="HorizontalNormalBorderBrush" StartPoint="0,0" EndPoint="1,0">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#CCC" Offset="0.0"/>
<GradientStop Color="#444" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="DefaultedBorderBrush" StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#777" Offset="0.0"/>
<GradientStop Color="#000" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="PressedBorderBrush" StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#444" Offset="0.0"/>
<GradientStop Color="#888" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<SolidColorBrush x:Key="DisabledBorderBrush" Color="#AAA" />
<SolidColorBrush x:Key="SolidBorderBrush" Color="#888" />
<SolidColorBrush x:Key="LightBorderBrush" Color="#AAA" />
<!-- Miscellaneous Brushes -->
<SolidColorBrush x:Key="GlyphBrush" Color="#444" />
<SolidColorBrush x:Key="LightColorBrush" Color="#DDD" />
<ControlTemplate x:Key="ComboBoxToggleButton" TargetType="ToggleButton">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="20" />
</Grid.ColumnDefinitions>
<Border
x:Name="Border"
Grid.ColumnSpan="2"
CornerRadius="2"
Background="{StaticResource NormalBrush}"
BorderBrush="{StaticResource NormalBorderBrush}"
BorderThickness="1" />
<Border
Grid.Column="0"
CornerRadius="2,0,0,2"
Margin="1"
Background="{StaticResource WindowBackgroundBrush}"
BorderBrush="{StaticResource NormalBorderBrush}"
BorderThickness="0,0,1,0" />
<Path
x:Name="Arrow"
Grid.Column="1"
Fill="{StaticResource GlyphBrush}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="M 0 0 L 4 4 L 8 0 Z"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="ToggleButton.IsMouseOver" Value="true">
<Setter TargetName="Border" Property="Background" Value="{StaticResource DarkBrush}" />
</Trigger>
<Trigger Property="ToggleButton.IsChecked" Value="true">
<Setter TargetName="Border" Property="Background" Value="{StaticResource PressedBrush}" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="Border" Property="Background" Value="{StaticResource DisabledBackgroundBrush}" />
<Setter TargetName="Border" Property="BorderBrush" Value="{StaticResource DisabledBorderBrush}" />
<Setter Property="Foreground" Value="{StaticResource DisabledForegroundBrush}"/>
<Setter TargetName="Arrow" Property="Fill" Value="{StaticResource DisabledForegroundBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<ControlTemplate x:Key="ComboBoxTextBox" TargetType="TextBox">
<Border x:Name="PART_ContentHost" Focusable="False" Background="{TemplateBinding Background}" />
</ControlTemplate>
<Style x:Key="{x:Type ComboBox}" TargetType="ComboBox">
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
<Setter Property="MinWidth" Value="120"/>
<Setter Property="MinHeight" Value="20"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBox">
<Grid>
<ToggleButton
Name="ToggleButton"
Template="{StaticResource ComboBoxToggleButton}"
Grid.Column="2"
Focusable="false"
IsChecked="{Binding Path=IsDropDownOpen,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}"
ClickMode="Press">
</ToggleButton>
<ContentPresenter
Name="ContentSite"
IsHitTestVisible="False"
Content="{TemplateBinding SelectionBoxItem}"
ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"
Margin="3,3,23,3"
VerticalAlignment="Center"
HorizontalAlignment="Left" />
<TextBox x:Name="PART_EditableTextBox"
Style="{x:Null}"
Template="{StaticResource ComboBoxTextBox}"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Margin="3,3,23,3"
Focusable="True"
Background="Transparent"
Visibility="Hidden"
IsReadOnly="{TemplateBinding IsReadOnly}"/>
<Popup
Name="Popup"
Placement="Bottom"
IsOpen="{TemplateBinding IsDropDownOpen}"
AllowsTransparency="True"
Focusable="False"
PopupAnimation="Slide">
<Grid
Name="DropDown"
SnapsToDevicePixels="True"
MinWidth="{TemplateBinding ActualWidth}"
MaxHeight="{TemplateBinding MaxDropDownHeight}">
<Border
x:Name="DropDownBorder"
Background="{StaticResource WindowBackgroundBrush}"
BorderThickness="1"
BorderBrush="{StaticResource SolidBorderBrush}"/>
<ScrollViewer Margin="4,6,4,6" SnapsToDevicePixels="True">
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
</ScrollViewer>
</Grid>
</Popup>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="HasItems" Value="false">
<Setter TargetName="DropDownBorder" Property="MinHeight" Value="95"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{StaticResource DisabledForegroundBrush}"/>
</Trigger>
<Trigger Property="IsGrouping" Value="true">
<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
</Trigger>
<Trigger SourceName="Popup" Property="Popup.AllowsTransparency" Value="true">
<Setter TargetName="DropDownBorder" Property="CornerRadius" Value="4"/>
<Setter TargetName="DropDownBorder" Property="Margin" Value="0,2,0,0"/>
</Trigger>
<Trigger Property="IsEditable"
Value="true">
<Setter Property="IsTabStop" Value="false"/>
<Setter TargetName="PART_EditableTextBox" Property="Visibility" Value="Visible"/>
<Setter TargetName="ContentSite" Property="Visibility" Value="Hidden"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
</Style.Triggers>
</Style>
<Style TargetType="TextBox">
<Setter Property="Background" Value="White"/>
<Setter Property="BorderBrush" Value="Black"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<Border Name="Bd" BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="true">
<ScrollViewer Name="PART_ContentHost" Background="{TemplateBinding Background}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Value="{StaticResource DisabledBackgroundBrush}" Property="Background" />
<Setter Value="{StaticResource DisabledForegroundBrush}" Property="Foreground" />
<Setter TargetName="PART_ContentHost" Property="Background" Value="{StaticResource DisabledBackgroundBrush}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<StackPanel>
<TextBox IsEnabled="False">TextBox</TextBox>
<ComboBox IsEnabled="False"/>
</StackPanel>
</Window>
You can use the below snippet :
Instead of checking for IsEnable property, use IsReadonly property of TextBox control.
<Style TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="LightSkyBlue" />
<Style.Triggers>
<Trigger Property="IsReadOnly" Value="True">
<Setter Property="Background" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
If You need to apply it for all the textbox controls, use the above code.
For specific textbox, just set the key and apply the style to that Textbox.
For this situation I like to set Focusable=false and set the background color to my desired value (in a data-bound trigger). This is maybe a little hacky, but so is rewriting the control template for the whole TextBox. An alternative to Focusable is IsReadyOnly, but that doesn't work for as many controls. It does ensure the caret disappears, though.
You never use the ControlTemplate you defined. Also, you want a Style, not (necessarily) a ControlTemplate.
I think you want something like the following:
<Canvas.Resources>
<SolidColorBrush x:Key="DisabledForegroundBrush" Color="Red" />
<SolidColorBrush x:Key="DisabledBackgroundBrush" Color="White" />
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="{StaticResource DisabledForegroundBrush}" />
<Setter Property="Background" Value="{StaticResource DisabledBackgroundBrush}" />
</Trigger>
</Style.Triggers>
</Style>
</Canvas.Resources>
If you look at the template of the textbox, you will notice that the template has a trigger for the IsEnabled property False, and sets it's border element "Bd" background color to SystemColors.ControlBrushKey.
If you override this color in a style, it will achieve what you want to do.
<Style TargetType="{x:Type TextBox}">
<Style.Resources>
<SolidColorBrush
x:Key="{x:Static SystemColors.ControlBrushKey}"
Color="{StaticResource MyNewTextBoxBackgroundColor}" />
</Style.Resources>
</Style>
Try to avoid redefining control templates where you can. They tend to add a lot of code overhead and can become difficult to maintain over time.
I would use the following code in the Loaded event:
ClassicBorderDecorator o = VisualTreeHelper.GetChild(this.textBox1, 0) as ClassicBorderDecorator;
if (o != null)
{
o.Background = new SolidColorBrush(Colors.Transparent);
}
By adding <Window.Resources> after <Window> and before <Grid> will make your text box behave like normal winforms textbox.
<Window x:Class="..." Height="330" Width="600" Loaded="Window_Loaded" WindowStartupLocation="CenterOwner">
<Window.Resources>
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="IsReadOnly" Value="True">
<Setter Property="Background" Value="LightGray" />
</Trigger>
<Trigger Property="IsReadOnly" Value="False">
<Setter Property="Background" Value="White" />
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
Code taken from following web page:
wpf: Selecting the Text in TextBox with IsReadOnly = true?
And style modified to match winforms. (Their appearance is enabled = false, not readonly = true)
And of course your textbox must have IsReadOnly="True" attribute set.
Okay, I've not done much WPF lately and this is confusing me.
I have a Style defined for RadioButton, which uses a ControlTemplate with a MultiTrigger. The gist is that I want a Border to become opaque when the mouse either hovers over it or when it's IsChecked is true.
So I have the MultiTrigger, which animates the Opacity in and out operating on 2 conditions; IsChecked is false and IsMouseOver is true. I've then got another 3 triggers. One set's the cursor to hand when the mouse is over it. Another set's the borders opacity to 0 when it's IsChecked is false and a final one to set opacity to 1 when IsChecked is true.
My problem is that that final trigger doesn't work the way I'm expecting. The RadioButton which is checked no longer satisfies the conditions for the MultiTrigger so the animations don't happen but the border's opacity goes back to 0 when I click.
Something has to be goind on with the MultiTrigger because commenting it out makes the other trigger work.
The code for the Style is below -
<Style TargetType="RadioButton" x:Key="MenuFlameButton">
<Setter Property="Width" Value="80"/>
<Setter Property="FontFamily" Value="/#SlabTallX"/>
<Setter Property="FontSize" Value="16"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="RadioButton">
<Grid>
<Border
BorderThickness="1,0,1,0"
BorderBrush="{StaticResource XWhiteX}">
</Border>
<Border x:Name="outerBorder"
Background="{TemplateBinding Background}"
OpacityMask="{StaticResource TallVerticalMask}">
</Border>
<ContentControl
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center">
<TextBlock x:Name="txt" Style="{StaticResource ButtonText}" IsHitTestVisible="False"
Text="{TemplateBinding Content}"
VerticalAlignment="Center"
HorizontalAlignment="Center"/>
</ContentControl>
</Grid>
<ControlTemplate.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition SourceName="outerBorder" Property="UIElement.IsMouseOver" Value="True"/>
<Condition Property="RadioButton.IsChecked" Value="False"/>
</MultiTrigger.Conditions>
<MultiTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="0:0:0.2" Storyboard.TargetName="outerBorder" Storyboard.TargetProperty="(UIElement.Opacity)" To="1"/>
</Storyboard>
</BeginStoryboard>
</MultiTrigger.EnterActions>
<MultiTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="0:0:0.5" Storyboard.TargetName="outerBorder" Storyboard.TargetProperty="(UIElement.Opacity)" To="0"/>
</Storyboard>
</BeginStoryboard>
</MultiTrigger.ExitActions>
</MultiTrigger>
<Trigger Property="UIElement.IsMouseOver" Value="True">
<Setter Property="Cursor" Value="Hand"/>
</Trigger>
<Trigger Property="RadioButton.IsChecked" Value="False">
<Setter TargetName="outerBorder" Property="Opacity" Value="0"/>
</Trigger>
<Trigger Property="RadioButton.IsChecked" Value="True">
<Setter TargetName="outerBorder" Property="Opacity" Value="1"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I'm really not sure why the border fades back out when I click it.
As always, any help will be greatly appreciated.
EDIT: I've included a Kaxaml friendly snippet to make it a bit easier for people to help. Just paste this code in.
<Page.Resources>
<Style x:Key="MainWindow" TargetType="Window">
<Setter Property="Height" Value="600"/>
<Setter Property="Height" Value="600"/>
<Setter Property="Height" Value="600"/>
<Setter Property="Height" Value="600"/>
<Setter Property="Height" Value="600"/>
</Style>
<Style x:Key="SplashScreenWindow" TargetType="Window">
<Setter Property="Height" Value="200"/>
<Setter Property="Width" Value="450"/>
<Setter Property="AllowsTransparency" Value="True"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="WindowStyle" Value="None"/>
<Setter Property="ResizeMode" Value="NoResize"/>
<Setter Property="Opacity" Value="1"/>
</Style>
<Style x:Key="ActivityBorder" TargetType="Border">
<Setter Property="BorderThickness" Value="0,0,0,1"/>
<Setter Property="Background" Value="#0555"/>
<Setter Property="BorderBrush" Value="#999"/>
<Setter Property="Margin" Value="10,3,10,3"/>
</Style>
<Style x:Key="Title" TargetType="TextBlock">
<Setter Property="FontFamily" Value="/#Harabara"/>
<Setter Property="FontSize" Value="42"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Foreground" Value="#eee"/>
</Style>
<Style x:Key="SplashTitle" BasedOn="{StaticResource Title}" TargetType="TextBlock">
<Setter Property="FontSize" Value="56"/>
</Style>
<Style x:Key="SubTitle" TargetType="TextBlock">
<Setter Property="FontFamily" Value="/#SlabTallX"/>
<Setter Property="FontSize" Value="24"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Foreground" Value="#eee"/>
<Setter Property="Margin" Value="10"/>
</Style>
<Style x:Key="DescriptionText" TargetType="TextBlock">
<Setter Property="FontSize" Value="14"/>
<Setter Property="Foreground" Value="#eee"/>
<Setter Property="Margin" Value="5,5,5,15"/>
</Style>
<Style x:Key="Strap" TargetType="TextBlock">
<Setter Property="FontFamily" Value="/#SlabTallX"/>
<Setter Property="FontSize" Value="17"/>
<Setter Property="Foreground" Value="#ccc"/>
</Style>
<Style x:Key="StrapActive" TargetType="TextBlock">
<Setter Property="FontFamily" Value="/#SlabTallX"/>
<Setter Property="FontSize" Value="17"/>
<Setter Property="Foreground" Value="#fff"/>
</Style>
<Style x:Key="StrapBold" TargetType="TextBlock">
<Setter Property="FontFamily" Value="/#SlabTallX"/>
<Setter Property="FontSize" Value="17"/>
<Setter Property="Foreground" Value="#cc9"/>
</Style>
<Style x:Key="ButtonText" BasedOn="{StaticResource Strap}" TargetType="TextBlock">
<Setter Property="FontSize" Value="14"/>
</Style>
<Style x:Key="FormLabel" TargetType="Label">
<Setter Property="FontSize" Value="14"/>
<Setter Property="Foreground" Value="#ccc"/>
<Setter Property="Width" Value="200"/>
<Setter Property="Margin" Value="5,5,10,5"/>
</Style>
<Style x:Key="StatusLabel" TargetType="Label">
<Setter Property="FontSize" Value="15"/>
<Setter Property="Foreground" Value="#ccc"/>
<Setter Property="Margin" Value="0,-5,0,0"/>
</Style>
<Style x:Key="StatusText" TargetType="TextBlock">
<Setter Property="FontSize" Value="13"/>
<Setter Property="Foreground" Value="#cc9"/>
<Setter Property="Margin" Value="5,-2,0,0"/>
<Setter Property="TextWrapping" Value="Wrap"/>
<Setter Property="Foreground" Value="#cc9"/>
</Style>
<Style x:Key="FormTextBox" TargetType="TextBox">
<Setter Property="Width" Value="250"/>
<Setter Property="Height" Value="25"/>
</Style>
<Style x:Key="PageBorder" TargetType="Border">
<Setter Property="Padding" Value="10,0,10,10"/>
<Setter Property="BorderThickness" Value="2"/>
</Style>
<RadialGradientBrush x:Key="GreyRadial" Center="0,0" RadiusX="1" RadiusY="1">
<GradientStop Color="#555" Offset="0"/>
<GradientStop Color="#333" Offset="1"/>
</RadialGradientBrush>
<LinearGradientBrush x:Key="StripBorderDarkGrey" StartPoint="0,0" EndPoint="1,0">
<GradientStop Color="#222" Offset="0"/>
<GradientStop Color="#111" Offset=".25"/>
<GradientStop Color="#444" Offset="1"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="StripBorderDarkRed" StartPoint="0,0" EndPoint="1,0">
<GradientStop Color="#222" Offset="0"/>
<GradientStop Color="#111" Offset=".25"/>
<GradientStop Color="#644" Offset="1"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="TitleBar" StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#777" Offset="0"/>
<GradientStop Color="#555" Offset=".3"/>
<GradientStop Color="#777" Offset="1"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="ColorFlame" StartPoint="0,0" EndPoint="1,0">
<GradientStop Color="#f00" Offset="0"/>
<GradientStop Color="#0f00" Offset="0.15"/>
<GradientStop Color="#f0f" Offset="0.25"/>
<GradientStop Color="#0f0f" Offset="0.35"/>
<GradientStop Color="#00f" Offset="0.5"/>
<GradientStop Color="#000f" Offset="0.62"/>
<GradientStop Color="#0f0" Offset="0.75"/>
<GradientStop Color="#00f0" Offset="0.85"/>
<GradientStop Color="#ff0" Offset="1"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="XWhiteX" StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="Transparent" Offset="0"/>
<GradientStop Color="#ddd" Offset="0.5"/>
<GradientStop Color="Transparent" Offset="1"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="ColorFlameRed" StartPoint="0,0" EndPoint="1,0">
<GradientStop Color="#f00" Offset="0"/>
<GradientStop Color="#0f00" Offset="0.15"/>
<GradientStop Color="#f00" Offset="0.25"/>
<GradientStop Color="#0f00" Offset="0.35"/>
<GradientStop Color="#f00" Offset="0.5"/>
<GradientStop Color="#0f00" Offset="0.62"/>
<GradientStop Color="#f00" Offset="0.75"/>
<GradientStop Color="#0f00" Offset="0.85"/>
<GradientStop Color="#f00" Offset="1"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="ColorFlamePurple" StartPoint="0,0" EndPoint="1,0">
<GradientStop Color="#f0f" Offset="0"/>
<GradientStop Color="#0f0f" Offset="0.15"/>
<GradientStop Color="#f0f" Offset="0.25"/>
<GradientStop Color="#0f0f" Offset="0.35"/>
<GradientStop Color="#f0f" Offset="0.5"/>
<GradientStop Color="#0f0f" Offset="0.62"/>
<GradientStop Color="#f0f" Offset="0.75"/>
<GradientStop Color="#0f0f" Offset="0.85"/>
<GradientStop Color="#f0f" Offset="1"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="ColorFlameBlue" StartPoint="0,0" EndPoint="1,0">
<GradientStop Color="#00f" Offset="0"/>
<GradientStop Color="#000f" Offset="0.15"/>
<GradientStop Color="#00f" Offset="0.25"/>
<GradientStop Color="#000f" Offset="0.35"/>
<GradientStop Color="#00f" Offset="0.5"/>
<GradientStop Color="#000f" Offset="0.62"/>
<GradientStop Color="#00f" Offset="0.75"/>
<GradientStop Color="#000f" Offset="0.85"/>
<GradientStop Color="#00f" Offset="1"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="ColorFlameGreen" StartPoint="0,0" EndPoint="1,0">
<GradientStop Color="#0f0" Offset="0"/>
<GradientStop Color="#00f0" Offset="0.15"/>
<GradientStop Color="#0f0" Offset="0.25"/>
<GradientStop Color="#00f0" Offset="0.35"/>
<GradientStop Color="#0f0" Offset="0.5"/>
<GradientStop Color="#00f0" Offset="0.62"/>
<GradientStop Color="#0f0" Offset="0.75"/>
<GradientStop Color="#00f0" Offset="0.85"/>
<GradientStop Color="#0f0" Offset="1"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="ColorFlameYellow" StartPoint="0,0" EndPoint="1,0">
<GradientStop Color="#ff0" Offset="0"/>
<GradientStop Color="#0ff0" Offset="0.15"/>
<GradientStop Color="#ff0" Offset="0.25"/>
<GradientStop Color="#0ff0" Offset="0.35"/>
<GradientStop Color="#ff0" Offset="0.5"/>
<GradientStop Color="#0ff0" Offset="0.62"/>
<GradientStop Color="#ff0" Offset="0.75"/>
<GradientStop Color="#0ff0" Offset="0.85"/>
<GradientStop Color="#ff0" Offset="1"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="ColorFlameSectionRed" StartPoint="0,0" EndPoint="1,0">
<GradientStop Color="#0f00" Offset="0"/>
<GradientStop Color="#f00" Offset="0.5"/><!--red-->
<GradientStop Color="#0f00" Offset="1"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="ColorFlameSectionPurple" StartPoint="0,0" EndPoint="1,0">
<GradientStop Color="#0f0f" Offset="0"/>
<GradientStop Color="#f0f" Offset="0.5"/><!--purple-->
<GradientStop Color="#0f0f" Offset="1"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="ColorFlameSectionBlue" StartPoint="0,0" EndPoint="1,0">
<GradientStop Color="#000f" Offset="0"/>
<GradientStop Color="#00f" Offset="0.5"/><!--blue-->
<GradientStop Color="#000f" Offset="1"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="ColorFlameSectionGreen" StartPoint="0,0" EndPoint="1,0">
<GradientStop Color="#00f0" Offset="0"/>
<GradientStop Color="#0f0" Offset="0.5"/><!--green-->
<GradientStop Color="#00f0" Offset="1"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="ColorFlameSectionYellow" StartPoint="0,0" EndPoint="1,0">
<GradientStop Color="#0ff0" Offset="0"/>
<GradientStop Color="#ff0" Offset="0.5"/><!--yellow-->
<GradientStop Color="#0ff0" Offset="1"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="ShortVerticalMask" StartPoint="0,1" EndPoint="0,0">
<GradientStop Color="#6FFF" Offset="0"/>
<GradientStop Color="Transparent" Offset="0.25"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="VerticalMask" StartPoint="0,1" EndPoint="0,0">
<GradientStop Color="#6FFF" Offset="0"/>
<GradientStop Color="Transparent" Offset="0.5"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="TallVerticalMask" StartPoint="0,1" EndPoint="0,0">
<GradientStop Color="#6FFF" Offset="0"/>
<GradientStop Color="Transparent" Offset="0.9"/>
</LinearGradientBrush>
</Page.Resources>
<DockPanel x:Name="menuDock" DockPanel.Dock="Top" LastChildFill="False" Background="Black">
<DockPanel.Resources>
<Style TargetType="RadioButton" x:Key="MenuFlameButton">
<Setter Property="Width" Value="80"/>
<Setter Property="FontFamily" Value="/#SlabTallX"/>
<Setter Property="FontSize" Value="16"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="RadioButton">
<Grid>
<Border
BorderThickness="1,0,1,0"
BorderBrush="{StaticResource XWhiteX}">
</Border>
<Border x:Name="outerBorder"
Background="{TemplateBinding Background}"
OpacityMask="{StaticResource TallVerticalMask}">
</Border>
<ContentControl
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center">
<TextBlock x:Name="txt" Style="{StaticResource ButtonText}" IsHitTestVisible="False"
Text="{TemplateBinding Content}"
VerticalAlignment="Center"
HorizontalAlignment="Center"/>
</ContentControl>
</Grid>
<ControlTemplate.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition SourceName="outerBorder" Property="UIElement.IsMouseOver" Value="True"/>
<Condition Property="RadioButton.IsChecked" Value="False"/>
</MultiTrigger.Conditions>
<MultiTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="0:0:0.2" Storyboard.TargetName="outerBorder" Storyboard.TargetProperty="(UIElement.Opacity)" To="1"/>
</Storyboard>
</BeginStoryboard>
</MultiTrigger.EnterActions>
<MultiTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="0:0:0.5" Storyboard.TargetName="outerBorder" Storyboard.TargetProperty="(UIElement.Opacity)" To="0"/>
</Storyboard>
</BeginStoryboard>
</MultiTrigger.ExitActions>
</MultiTrigger>
<Trigger Property="UIElement.IsMouseOver" Value="True">
<Setter Property="Cursor" Value="Hand"/>
</Trigger>
<Trigger Property="RadioButton.IsChecked" Value="False">
<Setter TargetName="outerBorder" Property="Opacity" Value="0"/>
</Trigger>
<Trigger Property="RadioButton.IsChecked" Value="True">
<Setter TargetName="outerBorder" Property="Opacity" Value="1"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</DockPanel.Resources>
<RadioButton
Margin="2,0,10,0"
Background="{StaticResource ColorFlameSectionYellow}"
Content="Tools"
DockPanel.Dock="Right"
Style="{StaticResource MenuFlameButton}"
Tag="Tools"/>
<RadioButton
Margin="2,0,2,0"
Background="{StaticResource ColorFlameSectionGreen}"
Content="Settings"
DockPanel.Dock="Right"
Style="{StaticResource MenuFlameButton}"
Tag="Settings"/>
<RadioButton
Margin="2,0,2,0"
Background="{StaticResource ColorFlameSectionBlue}"
Content="Event Log"
DockPanel.Dock="Right"
Style="{StaticResource MenuFlameButton}"
Tag="EventLog"/>
<RadioButton
Margin="2,0,2,0"
Background="{StaticResource ColorFlameSectionPurple}"
Content="Queue"
DockPanel.Dock="Right"
Style="{StaticResource MenuFlameButton}"
Tag="Queue"/>
<RadioButton
Margin="2,0,2,0"
Background="{StaticResource ColorFlameSectionRed}"
Content="Debug"
DockPanel.Dock="Right"
Style="{StaticResource MenuFlameButton}"
Tag="Debug"/>
</DockPanel>
Here is a solution,
I modified outerBorder to specify Opacity=0:
<Border x:Name="outerBorder" Background="{TemplateBinding Background}" OpacityMask="{StaticResource TallVerticalMask}" Opacity="0">
</Border>
Named the ExitAction's storyboard:
<MultiTrigger.ExitActions>
<BeginStoryboard Name="ExitStoryBoard">
...
And replaced the triggers for RadioButton.IsChecked with this:
<Trigger Property="RadioButton.IsChecked" Value="True">
<Trigger.EnterActions>
<PauseStoryboard BeginStoryboardName="ExitStoryBoard"/>
</Trigger.EnterActions>
<Trigger.Setters>
<Setter TargetName="outerBorder" Property="Opacity" Value="1"/>
</Trigger.Setters>
<Trigger.ExitActions>
<ResumeStoryboard BeginStoryboardName="ExitStoryBoard"/>
</Trigger.ExitActions>
</Trigger>