Reputation: 21
A little help, please ... I have this ResourceDictionary to style buttons. There is a "Base button style" and now I am working on a button which will have a drop down content menu where the user can make a selection. As you will notice in the code below, I had to copy and paste the visual states from the base button style to the dropdown button style if I wanted both button to look the same when focused, mouse over, etc. But what if I have to make a change in the future? Then I will have to remember to apply the change in both styles - perhaps there might be more than 2 styles if this library keeps growing.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Base button style -->
<Style x:Key="winFormButton" TargetType="Button">
<!-- Set Default Background and Border -->
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlLightBrushKey}}"/>
<Setter Property="BorderBrush" Value="{DynamicResource {x:Static SystemColors.ControlDarkBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Padding" Value="4,2"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Width" Value="73"/>
<Setter Property="Height" Value="21"/>
<!-- Control Template -->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
<ContentPresenter x:Name="contentPresenter" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
<!-- Visual States -->
<ControlTemplate.Triggers>
<!-- Mouse Over -->
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="BorderThickness" Value="1"/>
<Setter TargetName="border" Property="Background" Value="{DynamicResource {x:Static SystemColors.InactiveBorderBrushKey}}"/>
<Setter TargetName="border" Property="BorderBrush" Value="{DynamicResource {x:Static SystemColors.HotTrackBrushKey}}"/>
</Trigger>
<!-- Pressed -->
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="border" Property="Background" Value="{DynamicResource {x:Static SystemColors.GradientInactiveCaptionBrushKey}}"/>
<Setter TargetName="border" Property="BorderBrush" Value="{DynamicResource {x:Static SystemColors.HotTrackBrushKey}}"/>
</Trigger>
<!-- Disabled -->
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="border" Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlLightBrushKey}}"/>
<Setter TargetName="border" Property="BorderBrush" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
<Setter TargetName="contentPresenter" Property="Effect">
<Setter.Value>
<DropShadowEffect Color="{DynamicResource {x:Static SystemColors.HighlightTextColorKey}}" Direction="660" ShadowDepth="1.2" BlurRadius="0" Opacity="1"/>
</Setter.Value>
</Setter>
</Trigger>
<!-- Focused -->
<Trigger Property="IsKeyboardFocused" Value="True">
<Setter TargetName="border" Property="BorderThickness" Value="2"/>
<Setter TargetName="border" Property="BorderBrush" Value="{DynamicResource {x:Static SystemColors.HotTrackBrushKey}}"/>
</Trigger>
<!-- Focused and Mouse Over -->
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsKeyboardFocused" Value="True"/>
<Condition Property="IsMouseOver" Value="True"/>
</MultiTrigger.Conditions>
<Setter TargetName="border" Property="BorderThickness" Value="1"/>
<Setter TargetName="border" Property="BorderBrush" Value="{DynamicResource {x:Static SystemColors.HotTrackBrushKey}}"/>
</MultiTrigger>
<!-- Default and Not Focused -->
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsDefaulted" Value="True"/>
<Condition Property="IsFocused" Value="False"/>
</MultiTrigger.Conditions>
<Setter Property="BorderThickness" Value="2"/>
<Setter Property="BorderBrush" Value="{DynamicResource {x:Static SystemColors.HotTrackBrushKey}}"/>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Dropdown button style -->
<Style x:Key="dropdownWinFormButton" TargetType="Button" BasedOn="{StaticResource winFormButton}">
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<Border x:Name="border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<ContentPresenter x:Name="contentPresenter" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Margin="6,-2,0,0"/>
<Path HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0,0,5,0" Data="M 2 2 L 6 6 L 10 2" Stroke="{TemplateBinding Foreground}" StrokeThickness="1" Fill="Transparent"/>
</Grid>
</Border>
</Grid>
<!-- Visual States -->
<ControlTemplate.Triggers>
<!-- Mouse Over -->
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="BorderThickness" Value="1"/>
<Setter TargetName="border" Property="Background" Value="{DynamicResource {x:Static SystemColors.InactiveBorderBrushKey}}"/>
<Setter TargetName="border" Property="BorderBrush" Value="{DynamicResource {x:Static SystemColors.HotTrackBrushKey}}"/>
</Trigger>
<!-- Pressed -->
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="border" Property="Background" Value="{DynamicResource {x:Static SystemColors.GradientInactiveCaptionBrushKey}}"/>
<Setter TargetName="border" Property="BorderBrush" Value="{DynamicResource {x:Static SystemColors.HotTrackBrushKey}}"/>
</Trigger>
<!-- Disabled -->
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="border" Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlLightBrushKey}}"/>
<Setter TargetName="border" Property="BorderBrush" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
<Setter TargetName="contentPresenter" Property="Effect">
<Setter.Value>
<DropShadowEffect Color="{DynamicResource {x:Static SystemColors.HighlightTextColorKey}}" Direction="660" ShadowDepth="1.2" BlurRadius="0" Opacity="1"/>
</Setter.Value>
</Setter>
</Trigger>
<!-- Focused -->
<Trigger Property="IsKeyboardFocused" Value="True">
<Setter TargetName="border" Property="BorderThickness" Value="2"/>
<Setter TargetName="border" Property="BorderBrush" Value="{DynamicResource {x:Static SystemColors.HotTrackBrushKey}}"/>
</Trigger>
<!-- Focused and Mouse Over -->
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsKeyboardFocused" Value="True"/>
<Condition Property="IsMouseOver" Value="True"/>
</MultiTrigger.Conditions>
<Setter TargetName="border" Property="BorderThickness" Value="1"/>
<Setter TargetName="border" Property="BorderBrush" Value="{DynamicResource {x:Static SystemColors.HotTrackBrushKey}}"/>
</MultiTrigger>
<!-- Default and Not Focused -->
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsDefaulted" Value="True"/>
<Condition Property="IsFocused" Value="False"/>
</MultiTrigger.Conditions>
<Setter Property="BorderThickness" Value="2"/>
<Setter Property="BorderBrush" Value="{DynamicResource {x:Static SystemColors.HotTrackBrushKey}}"/>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Is there a way to apply the Visual States (i.e. the ControlTemplate.Triggers) to both styles without having to copy the entire code so that when a change/a correction is needed this will be done in a single place?
Upvotes: 0
Views: 46
Reputation: 21
Thank you for the suggestions. I was not able to move the Triggers in ControlTemplate.Triggers to Style.Triggers as many properties were no accessible in Style.Triggers. After scratching my head like a lot I managed to improve this situation using the Property="HorizontalContentAlignment" as trigger to set the content's margin and to show/hide the dropdown arrow. If I decide to add another style things might get trickier but for the time being, this seems to work.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- winFormButtonControlTemplate -->
<ControlTemplate x:Key="winFormButtonControlTemplate" TargetType="Button">
<Border x:Name="border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<AccessText x:Name="content"
Text="{TemplateBinding Content}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"/>
<Grid x:Name="dropdownArrowGrid" Visibility="Collapsed">
<Path VerticalAlignment="Center"
HorizontalAlignment="Right"
Margin="0,0,5,0"
Data="M 2 2 L 6 6 L 10 2"
Stroke="{TemplateBinding Foreground}"
StrokeThickness="1"
Fill="Transparent"/>
</Grid>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="HorizontalContentAlignment" Value="Center">
<Setter TargetName="content" Property="Margin" Value="0,0,0,0"/>
</Trigger>
<Trigger Property="HorizontalContentAlignment" Value="Left">
<Setter TargetName="content" Property="Margin" Value="6,-2,0,0"/>
<Setter TargetName="dropdownArrowGrid" Property="Visibility" Value="Visible"/>
</Trigger>
<!-- Mouse Over -->
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="BorderThickness" Value="1"/>
<Setter TargetName="border" Property="Background" Value="{DynamicResource {x:Static SystemColors.InactiveBorderBrushKey}}"/>
<Setter TargetName="border" Property="BorderBrush" Value="{DynamicResource {x:Static SystemColors.HotTrackBrushKey}}"/>
</Trigger>
<!-- Pressed -->
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="border" Property="Background" Value="{DynamicResource {x:Static SystemColors.GradientInactiveCaptionBrushKey}}"/>
<Setter TargetName="border" Property="BorderBrush" Value="{DynamicResource {x:Static SystemColors.HotTrackBrushKey}}"/>
</Trigger>
<!-- Disabled -->
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="border" Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlLightBrushKey}}"/>
<Setter TargetName="border" Property="BorderBrush" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
<Setter TargetName="content" Property="Effect">
<Setter.Value>
<DropShadowEffect Color="{DynamicResource {x:Static SystemColors.HighlightTextColorKey}}" Direction="660" ShadowDepth="1.2" BlurRadius="0" Opacity="1"/>
</Setter.Value>
</Setter>
</Trigger>
<!-- Focused -->
<Trigger Property="IsKeyboardFocused" Value="True">
<Setter TargetName="border" Property="BorderThickness" Value="2"/>
<Setter TargetName="border" Property="BorderBrush" Value="{DynamicResource {x:Static SystemColors.HotTrackBrushKey}}"/>
</Trigger>
<!-- Focused and Mouse Over -->
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsKeyboardFocused" Value="True"/>
<Condition Property="IsMouseOver" Value="True"/>
</MultiTrigger.Conditions>
<Setter TargetName="border" Property="BorderThickness" Value="1"/>
<Setter TargetName="border" Property="BorderBrush" Value="{DynamicResource {x:Static SystemColors.HotTrackBrushKey}}"/>
</MultiTrigger>
<!-- Default and Not Focused -->
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsDefaulted" Value="True"/>
<Condition Property="IsFocused" Value="False"/>
</MultiTrigger.Conditions>
<Setter Property="BorderThickness" Value="2"/>
<Setter Property="BorderBrush" Value="{DynamicResource {x:Static SystemColors.HotTrackBrushKey}}"/>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<!-- winFormButton -->
<Style x:Key="winFormButton" TargetType="Button">
<!-- Set Default Background and Border -->
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlLightBrushKey}}"/>
<Setter Property="BorderBrush" Value="{DynamicResource {x:Static SystemColors.ControlDarkBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Padding" Value="4,2"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Width" Value="73"/>
<Setter Property="Height" Value="21"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Template" Value="{StaticResource winFormButtonControlTemplate}"/>
</Style>
<!-- dropdownWinFormButton -->
<Style x:Key="dropdownWinFormButton" TargetType="Button" BasedOn="{StaticResource winFormButton}">
<Setter Property="HorizontalContentAlignment" Value="Left"/>
</Style>
<!-- Style for MenuItem -->
<Style TargetType="MenuItem">
<Setter Property="Command" Value="{Binding DataContext.OpenDropdownCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}"/>
</Style>
</ResourceDictionary>
Upvotes: 0