I'm trying to edit the default template of a button for a WPF application,the "MouseEnter" and "MouseLeave" events are working,the problem is with the "IsPressed" event that basically seems to not be triggered.I also removed the
RenderPressed="{TemplateBinding IsPressed}"
part but the button just seems to ignore my IsPressed event
Here's the code:
<LinearGradientBrush x:Key="ButtonNormalBackground" EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#F3F3F3" Offset="0"/>
<GradientStop Color="#EBEBEB" Offset="0.5"/>
<GradientStop Color="#DDDDDD" Offset="0.5"/>
<GradientStop Color="#CDCDCD" Offset="1"/>
</LinearGradientBrush>
<SolidColorBrush x:Key="ButtonNormalBorder" Color="#FF707070"/>
<Style x:Key="ButtonDark1" TargetType="{x:Type Button}">
<Setter Property="FocusVisualStyle" Value="{StaticResource ButtonFocusVisual}"/>
<Setter Property="Background" Value="{StaticResource ButtonNormalBackground}"/>
<Setter Property="BorderBrush" Value="{StaticResource ButtonNormalBorder}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Padding" Value="1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Themes:ButtonChrome x:Name="Chrome" BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" RenderDefaulted="{TemplateBinding IsDefaulted}" SnapsToDevicePixels="true">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Themes:ButtonChrome>
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="Control.MouseEnter">
<BeginStoryboard>
<Storyboard >
<DoubleAnimation Duration="0:0:0.3" To="0.8" Storyboard.TargetProperty="Opacity"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="Control.MouseLeave">
<BeginStoryboard>
<Storyboard >
<DoubleAnimation Duration="0:0:0.3" To="0.5" Storyboard.TargetProperty="Opacity"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<Trigger Property="IsKeyboardFocused" Value="true">
<Setter Property="RenderDefaulted" TargetName="Chrome" Value="false"/>
</Trigger>
<Trigger Property="ToggleButton.IsChecked" Value="true">
<Setter Property="RenderPressed" TargetName="Chrome" Value="true"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="#ADADAD"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Foreground" Value="LightBlue"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Thanks in advance.
Once again, we have a question where someone has messed up their ControlTemplate and wants someone else to fix it. The answer is always the same... start with the default ControlTemplate for your Button. You can find the default ControlTemplate for your Button in the Button Styles and Templates page on MSDN.
If you look at the linked page, you'll see a VisualStateManager.VisualStateGroups collection and inside that collection, you'll find a VisualState named Pressed. A little further up, you should see this:
<VisualTransition GeneratedDuration="0" To="Pressed" />
These are what manage the visual Pressed state.
When altering a default ControlTemplate, it is best to start with the whole default XAML and first get that working in your custom ControlTemplate. Once you have it working, then you can start to manipulate it, bit by bit and regularly checking it after every few changes. Then, if it doesn't work one time, you can just undo the last few changes and find out what you did wrong.
Related
I am working on a WPF application which has a styled TabControl.
We have a requirement where we need to show/hide the TabControl as per user selection. For this I set the Visibility of TabControl to Collapsed and then to Visible again when required.
The problem I am facing is that when I hide the TabControl and show it again the text in the TabHeader reverts back to the original colour.
Further I have come to notice that styles/colors of all the texts in the TabHeaders seems to reset.
Here is the Style for TabControl and TabHeader:
<Style x:Key="g_TabControlStyle" TargetType="{x:Type TabControl}">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="Padding" Value="4,4,4,4"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="BorderBrush" Value="{StaticResource TabControlNormalBorderBrush}"/>
<Setter Property="Background" Value="{StaticResource TabControlPaneTopNormalBackground}"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<Grid ClipToBounds="true" SnapsToDevicePixels="true" KeyboardNavigation.TabNavigation="Local">
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="ColumnDefinition0"/>
<ColumnDefinition x:Name="ColumnDefinition1" Width="0"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition x:Name="RowDefinition0" Height="Auto"/>
<RowDefinition x:Name="RowDefinition1" Height="*"/>
</Grid.RowDefinitions>
<TabPanel x:Name="HeaderPanel" Grid.Column="0" IsItemsHost="true" Margin="0,2,2,0" Grid.Row="0" KeyboardNavigation.TabIndex="1" Panel.ZIndex="1"/>
<Border x:Name="ContentPanel" BorderThickness="0,0,1,1" Grid.Column="0" KeyboardNavigation.DirectionalNavigation="Contained" Grid.Row="1" KeyboardNavigation.TabIndex="2" KeyboardNavigation.TabNavigation="Local">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
<Border Background="{TemplateBinding Background}">
<ContentPresenter x:Name="PART_SelectedContentHost" ContentSource="SelectedContent" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
</Border>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="TabStripPlacement" Value="Bottom">
<Setter Property="Grid.Row" TargetName="HeaderPanel" Value="1"/>
<Setter Property="Grid.Row" TargetName="ContentPanel" Value="0"/>
<Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
<Setter Property="Height" TargetName="RowDefinition1" Value="Auto"/>
<Setter Property="Margin" TargetName="HeaderPanel" Value="0,0,2,2"/>
<Setter Property="Background" Value="{StaticResource TabControlPaneBottomNormalBackground}"/>
</Trigger>
<Trigger Property="TabStripPlacement" Value="Left">
<Setter Property="Grid.Row" TargetName="HeaderPanel" Value="0"/>
<Setter Property="Grid.Row" TargetName="ContentPanel" Value="0"/>
<Setter Property="Grid.Column" TargetName="HeaderPanel" Value="0"/>
<Setter Property="Grid.Column" TargetName="ContentPanel" Value="1"/>
<Setter Property="Width" TargetName="ColumnDefinition0" Value="Auto"/>
<Setter Property="Width" TargetName="ColumnDefinition1" Value="*"/>
<Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
<Setter Property="Height" TargetName="RowDefinition1" Value="0"/>
<Setter Property="Margin" TargetName="HeaderPanel" Value="2,2,-1,2"/>
<Setter Property="Background" Value="{StaticResource TabControlPaneLeftNormalBackground}"/>
</Trigger>
<Trigger Property="TabStripPlacement" Value="Right">
<Setter Property="Grid.Row" TargetName="HeaderPanel" Value="0"/>
<Setter Property="Grid.Row" TargetName="ContentPanel" Value="0"/>
<Setter Property="Grid.Column" TargetName="HeaderPanel" Value="1"/>
<Setter Property="Grid.Column" TargetName="ContentPanel" Value="0"/>
<Setter Property="Width" TargetName="ColumnDefinition0" Value="*"/>
<Setter Property="Width" TargetName="ColumnDefinition1" Value="Auto"/>
<Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
<Setter Property="Height" TargetName="RowDefinition1" Value="0"/>
<Setter Property="Margin" TargetName="HeaderPanel" Value="-1,2,2,2"/>
<Setter Property="Background" Value="{StaticResource TabControlPaneRightNormalBackground}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="g_TabItemStyle" TargetType="{x:Type TabItem}">
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Padding" Value="12,2,12,2"/>
<Setter Property="BorderThickness" Value="1,1,1,0"/>
<Setter Property="BorderBrush" Value="{StaticResource TabControlNormalBorderBrush}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="Background" Value="{StaticResource TabItemNormalBackground}"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Border SnapsToDevicePixels="true" MinWidth="90" MaxWidth="190">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver"/>
<VisualState x:Name="Disabled"/>
</VisualStateGroup>
<VisualStateGroup x:Name="SelectionStates">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="Unselected">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="border1">
<EasingDoubleKeyFrame KeyTime="0" Value="0.2"/>
</DoubleAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground.Color" Storyboard.TargetName="contentPresenter">
<EasingColorKeyFrame KeyTime="0" Value="#8CFFFFFF"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Selected"/>
</VisualStateGroup>
<VisualStateGroup x:Name="FocusStates">
<VisualState x:Name="Unfocused"/>
<VisualState x:Name="Focused"/>
</VisualStateGroup>
<VisualStateGroup x:Name="ValidationStates">
<VisualState x:Name="Valid"/>
<VisualState x:Name="InvalidFocused"/>
<VisualState x:Name="InvalidUnfocused"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid Margin="0,0,1,0">
<Grid x:Name="Transform">
<Border x:Name="border1" Background="White"/>
</Grid>
<Border x:Name="border" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}" Background="{x:Null}" BorderBrush="{x:Null}">
<ContentControl x:Name="contentPresenter" Content="{TemplateBinding Header}" HorizontalAlignment="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" FocusVisualStyle="{DynamicResource g_EmptyFocusVisualStyle}"/>
</Border>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" Value="{StaticResource TabItemHotBackground}"/>
</Trigger>
<Trigger Property="IsSelected" Value="true">
<Setter Property="Panel.ZIndex" Value="1"/>
<Setter Property="Background" Value="{StaticResource TabItemSelectedBackground}"/>
</Trigger>
<Trigger Property="Selector.IsSelected" Value="False">
<Setter Property="Foreground" Value="#8CFFFFFF"/>
</Trigger>
<Trigger Property="TabStripPlacement" Value="Bottom">
<Setter Property="LayoutTransform" TargetName="Transform">
<Setter.Value>
<ScaleTransform ScaleY="-1" ScaleX="1"/>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="TabStripPlacement" Value="Left">
<Setter Property="LayoutTransform" TargetName="Transform">
<Setter.Value>
<RotateTransform Angle="-90"/>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="TabStripPlacement" Value="Right">
<Setter Property="LayoutTransform" TargetName="Transform">
<Setter.Value>
<RotateTransform Angle="90"/>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
<Setter Property="Background" Value="{StaticResource TabItemDisabledBackground}"/>
<Setter Property="BorderBrush" Value="{StaticResource TabItemDisabledBorderBrush}"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="true"/>
<Condition Property="TabStripPlacement" Value="Top"/>
</MultiTrigger.Conditions>
<Setter Property="Margin" Value="-2,-2,-2,-1"/>
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="true"/>
<Condition Property="TabStripPlacement" Value="Bottom"/>
</MultiTrigger.Conditions>
<Setter Property="Margin" Value="-2"/>
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="true"/>
<Condition Property="TabStripPlacement" Value="Left"/>
</MultiTrigger.Conditions>
<Setter Property="Margin" Value="-2,-2,-1,-2"/>
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="true"/>
<Condition Property="TabStripPlacement" Value="Right"/>
</MultiTrigger.Conditions>
<Setter Property="Margin" Value="-1,-2,-2,-2"/>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Other resources are as:
<SolidColorBrush x:Key="TabControlNormalBorderBrush" Color="#919B9C"/>
<LinearGradientBrush x:Key="TabItemNormalBackground" EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#FFFFFFFF" Offset="0"/>
<GradientStop Color="#FFBDBEDE" Offset="1"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="TabItemHotBackground" EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#FFFFFFFF" Offset="0"/>
<GradientStop Color="#FFBDBEDE" Offset="1"/>
</LinearGradientBrush>
<SolidColorBrush x:Key="TabItemSelectedBackground" Color="#FFFCFCFE"/>
<SolidColorBrush x:Key="TabItemDisabledBackground" Color="#FFF5F4EA"/>
<SolidColorBrush x:Key="TabItemDisabledBorderBrush" Color="#FFC9C7BA"/>
<LinearGradientBrush x:Key="TabControlPaneTopNormalBackground" EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#FFFCFCFE" Offset="0"/>
<GradientStop Color="#FFF4F3EE" Offset="1"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="TabControlPaneBottomNormalBackground" EndPoint="0,0" StartPoint="0,1">
<GradientStop Color="#FFFCFCFE" Offset="0"/>
<GradientStop Color="#FFF4F3EE" Offset="1"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="TabControlPaneLeftNormalBackground" EndPoint="1,0" StartPoint="0,0">
<GradientStop Color="#FFFCFCFE" Offset="0"/>
<GradientStop Color="#FFF4F3EE" Offset="1"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="TabControlPaneRightNormalBackground" EndPoint="0,0" StartPoint="1,0">
<GradientStop Color="#FFFCFCFE" Offset="0"/>
<GradientStop Color="#FFF4F3EE" Offset="1"/>
</LinearGradientBrush>
I have tried giving/setting different colours(other than white) to the texts and then I came to notice that everything works as expected till the TabControl is hidden, but then all texts revert back to white as soon as the TabControl is hidden and then re-shown.
Does anyone know what could cause this sort of behaviour or what could be wrong with the above XAML?
The default behavior is the watermark disappears when the text box gets focus. I'd like to make the watermark content disappear only when the user types the first character and then reappear if the text is cleared. Anyone have a good way to accomplish this?
I've tweaked the default style for you. Now the watermark shows with the (slightly darker) default system "inactive text" color by default, and the watermark's opacity transitions to 0.4 when it receives focus but has no content. Once it has text, the watermark disappears completely. Looks pretty good, I think:
<LinearGradientBrush x:Key="TextBoxBorder" EndPoint="0,20" MappingMode="Absolute" StartPoint="0,0">
<GradientStop Color="#ABADB3" Offset="0.05" />
<GradientStop Color="#E2E3EA" Offset="0.07" />
<GradientStop Color="#E3E9EF" Offset="1" />
</LinearGradientBrush>
<LinearGradientBrush x:Key="TextBox_MouseOver" EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#5794BF" Offset="0.05" />
<GradientStop Color="#B7D5EA" Offset="0.07" />
<GradientStop Color="#C7E2F1" Offset="1" />
</LinearGradientBrush>
<LinearGradientBrush x:Key="TextBox_Focused" EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#3D7BAD" Offset="0.05" />
<GradientStop Color="#A4C9E3" Offset="0.07" />
<GradientStop Color="#B7D9ED" Offset="1" />
</LinearGradientBrush>
<SolidColorBrush x:Key="TextBox_DisabledBorder" Color="#ADB2B5" />
<SolidColorBrush x:Key="TextBox_DisabledBackground" Color="#F4F4F4" />
<DataTemplate x:Key="DefaultWatermarkTemplate">
<ContentControl Content="{Binding}" Foreground="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" Focusable="False" />
</DataTemplate>
<Style TargetType="{x:Type extToolkit:WatermarkTextBox}">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" />
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}" />
<Setter Property="BorderBrush" Value="{StaticResource TextBoxBorder}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Padding" Value="3" />
<Setter Property="AllowDrop" Value="true" />
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst" />
<Setter Property="Stylus.IsFlicksEnabled" Value="False" />
<Setter Property="WatermarkTemplate" Value="{StaticResource DefaultWatermarkTemplate}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type extToolkit:WatermarkTextBox}">
<Grid>
<Border x:Name="Border" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" CornerRadius="1" Background="{TemplateBinding Background}" />
<Border x:Name="MouseOverVisual" Opacity="0" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{StaticResource TextBox_MouseOver}" CornerRadius="1" />
<Border x:Name="FocusVisual" Opacity="0" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{StaticResource TextBox_Focused}" CornerRadius="1" />
<ScrollViewer x:Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
<ContentPresenter x:Name="PART_WatermarkHost"
Content="{TemplateBinding Watermark}"
ContentTemplate="{TemplateBinding WatermarkTemplate}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
IsHitTestVisible="False"
Margin="{TemplateBinding Padding}"
Visibility="Collapsed" />
</Grid>
<ControlTemplate.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="Text" Value="" />
</MultiTrigger.Conditions>
<MultiTrigger.Setters>
<Setter Property="Visibility" TargetName="PART_WatermarkHost" Value="Visible" />
</MultiTrigger.Setters>
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsKeyboardFocusWithin" Value="True" />
<Condition Property="Text" Value="" />
</MultiTrigger.Conditions>
<MultiTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="PART_WatermarkHost" Storyboard.TargetProperty="Opacity" To=".33" Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</MultiTrigger.EnterActions>
<MultiTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="PART_WatermarkHost" Storyboard.TargetProperty="Opacity" Duration="0:0:0.4" />
</Storyboard>
</BeginStoryboard>
</MultiTrigger.ExitActions>
</MultiTrigger>
<Trigger Property="Text" Value="">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="PART_WatermarkHost" Storyboard.TargetProperty="Opacity" Duration="0:0:0.4" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="PART_WatermarkHost" Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="MouseOverVisual" Property="Opacity" Value="1" />
</Trigger>
<Trigger Property="IsFocused" Value="True">
<Setter TargetName="FocusVisual" Property="Opacity" Value="1" />
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter TargetName="Border" Property="BorderBrush" Value="{StaticResource TextBox_DisabledBorder}" />
<Setter TargetName="Border" Property="Background" Value="{StaticResource TextBox_DisabledBackground}" />
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Easiest way to apply this throughout your application is to drop that XAML into Application.Resources in your App.xaml. Feel free to tweak the colors and opacity values.
In Expression Blend 4, I want to customize a button.
Select the button in the window, right-clicked it, "Edit Template" -> "Edit a Copy", select the location in "Button.xaml" which is resources dictionary. Next delete the Chrome, add a Border, add a ContentPresenter below the Border. Next, select the Border, then in "State Panel", select MouseOver and change both Background and 'BorderBrush'. But the appearance of others's also is changed to the same as the MouseOver state.
I specify the Brush with "System Brush Resources" in "Properties Panel".
Like this image:
I just changed the Background of MouseOver state.
but the Backgrounds of other states also were changed:
Button.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero">
<Style x:Key="ButtonFocusVisual">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle Margin="2" SnapsToDevicePixels="true" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Resource dictionary entries should be defined here. -->
<LinearGradientBrush x:Key="ButtonNormalBackground" EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#F3F3F3" Offset="0"/>
<GradientStop Color="#EBEBEB" Offset="0.5"/>
<GradientStop Color="#DDDDDD" Offset="0.5"/>
<GradientStop Color="#CDCDCD" Offset="1"/>
</LinearGradientBrush>
<SolidColorBrush x:Key="ButtonNormalBorder" Color="#FF707070"/>
<Style x:Key="ButtonStyle1" TargetType="{x:Type Button}">
<Setter Property="FocusVisualStyle" Value="{StaticResource ButtonFocusVisual}"/>
<Setter Property="Background" Value="{StaticResource ButtonNormalBackground}"/>
<Setter Property="BorderBrush" Value="{StaticResource ButtonNormalBorder}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Padding" Value="1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border BorderBrush="{DynamicResource {x:Static SystemColors.ActiveCaptionTextBrushKey}}" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.HotTrackBrushKey}}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver"/>
<VisualState x:Name="Pressed"/>
<VisualState x:Name="Disabled"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ContentPresenter/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsKeyboardFocused" Value="true"/>
<Trigger Property="ToggleButton.IsChecked" Value="true"/>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="#ADADAD"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
I have solve it. Firstly, select one state in "States Panel", then switch to “Objects and Timeline Panel” and add a "Border", next change it's appearance.
Like this:
Looking at the various open source themes available for WPF, I'm a bit surprised to see that colours aren't mapped to system colours. So if you change your overall system configuration, these themes won't change to suit.
Are there any themes that properly use the system colours, and if so, how do I write a button style that will leverage those colours?
To give an example, here's the style of a button:
<Style x:Key="specialButton" TargetType="Button">
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="FocusVisualStyle" Value="{StaticResource ButtonFocusVisual}"/>
<Setter Property="Background" Value="{StaticResource NormalBrush}"/>
<Setter Property="Margin" Value="2"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Name="border"
BorderThickness="1"
Background="{TemplateBinding Background}"
BorderBrush="{StaticResource NormalBorderBrush}"
Padding="1,1">
<ContentPresenter Name="content" HorizontalAlignment="Center" VerticalAlignment="Center" RecognizesAccessKey="True"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="BorderBrush" 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="IsDefaulted" Value="True">
<Setter TargetName="border" Property="BorderBrush" Value="{StaticResource DefaultedBorderBrush}"/>
</Trigger>
<Trigger Property="IsFocused" Value="True">
<Setter TargetName="border" Property="BorderBrush" Value="{StaticResource DefaultedBorderBrush}"/>
</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>
The question is, how to specify the named static resources so that they hook into the system colours? For example, the background might look like this:
<LinearGradientBrush x:Key="NormalBrush" StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="{DynamicResource {x:Static SystemColors.ControlLightLightColorKey}}" Offset="0.0"/>
<GradientStop Color="{DynamicResource {x:Static SystemColors.ControlLightColorKey}}" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
However this looks nothing like a standard button. If I use XAMLPAD to examine a button, I can see the following:
<LinearGradientBrush x:Key="NormalBrush" StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#FFF3F3F3" Offset="0.0"/>
<GradientStop Color="#FFEBEBEB" Offset="0.5"/>
<GradientStop Color="#FFDDDDDD" Offset="0.5"/>
<GradientStop Color="#FFCDCDCD" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
The colours used appear to be constants, and not based on System Colours.
I don't know about third-party themes, but the system colours are available in Xaml through the SystemColors class. This class exposes the keys of resources that can be used in your xaml in one of two ways:
<Border Background="{x:Static SystemColors.ControlDarkBrushKey}" />
or:
<Border Background="{StaticResource {x:Static SystemColors.ControlDarkBrushKey}}" />
Either of the above should give you a border with a background the same as the system's ControlDarkBrush colour. The documentation link I gave supplies the full list of available resources.
It's worth noting that SystemColors provides you with both a Brush for each colour available, and the colour itself - so if you want to create your own brush that fades from one system colour to another, you can create this easily.
I have a button style defined like this:
<LinearGradientBrush x:Key="Brush_NavButtonBorder0" StartPoint="0,0" EndPoint="0,1" >
<GradientStop Color="#00383f47" Offset="0" />
<GradientStop Color="#FF383f47" Offset="1" />
</LinearGradientBrush>
<LinearGradientBrush x:Key="Brush_NavButtonBorder4" StartPoint="0,0" EndPoint="0,1" >
<GradientStop Color="#FF414f5a" Offset="0" />
<GradientStop Color="#11414f5a" Offset="1" />
</LinearGradientBrush>
<LinearGradientBrush x:Key="Brush_NavButtonBackground" StartPoint="0,0" EndPoint="0,1" >
<GradientStop Color="#FF3f505a" Offset="0" />
<GradientStop Color="#FF37454e" Offset="0.75" />
<GradientStop Color="#FF2f3c44" Offset="1" />
</LinearGradientBrush>
<LinearGradientBrush x:Key="Brush_NavButtonPressedBackground" StartPoint="0,0" EndPoint="0,1" >
<GradientStop Color="#FF3f505a" Offset="1" />
<GradientStop Color="#FF37454e" Offset="0.25" />
<GradientStop Color="#FF2f3c44" Offset="0" />
</LinearGradientBrush>
<Style x:Key="NavigationButton" TargetType="Button">
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<Setter Property="Foreground" Value="Gainsboro" />
<Setter Property="FontSize" Value="14" />
<Setter Property="Background" Value="{StaticResource Brush_NavButtonBackground}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}" x:Name="MainControlTemplate">
<Grid>
<Border x:Name="outerBorder" CornerRadius="5" BorderThickness="1" BorderBrush="{StaticResource Brush_NavButtonBorder0}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True" />
<Border Margin="1" CornerRadius="4" BorderThickness="1" BorderBrush="{StaticResource Brush_NavButtonBorder4}" Background="Transparent" SnapsToDevicePixels="True">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Name="content"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<!--<Setter TargetName="outerBorder" Property="BorderBrush" Value="Gray" />-->
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetName="outerBorder"
Storyboard.TargetProperty="(Border.BorderBrush).(GradientBrush.GradientStops)[0].(GradientStop.Color)"
To="Gray"
Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="{StaticResource Brush_NavButtonPressedBackground}" />
<Setter TargetName="content" Property="RenderTransform" >
<Setter.Value>
<TranslateTransform X="2.0" Y="2.0" />
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value="0.5" />
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="True">
<Setter Property="FocusVisualStyle" Value="{StaticResource MyFocusVisualStyle}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
This style has a couple of problems:
1. When I MouseOver a button, all other buttons using this style react with the animation instead of just the button I'm over.
2. I would like to animate the color of the entire border instead of just the 0th gradient stop, but I can't seem to find a way to do this.
The commented line above the ColorAnimation section does almost exactly what I want except that it displays the gray BorderBrush immediately on MouseOver - I want it to display the gray BorderBrush with animation.
This seems like it should be pretty simple, but I can't figure out how to do this. Does anyone know how to do this the right way?
The reason it is changing the border on all the buttons is that you're actually changing the color in the gradient brush. And since the same gradient brush is shared among all the button instances with that style, the border for all the brushes changes.
There are a number of ways to resolve this, but one of which is to make the brush in question a resource of the style itself, so it won't be shared in the same way. The following code snippet demonstrates all you would need to change (remove Brush_NavButtonBorder0 from the top-level resources, and add it to the resources of the button style) :
EDIT: Including the full style with the updates
<Color x:Key="BorderColor">#00383f47</Color>
<!-- Other Brushes (NOT Brush_NavButtonBorder0) -->
<Style x:Key="NavigationButton" TargetType="Button">
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<Setter Property="Foreground" Value="Gainsboro" />
<Setter Property="FontSize" Value="14" />
<Setter Property="Background" Value="{StaticResource Brush_NavButtonBackground}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}" x:Name="MainControlTemplate">
<ControlTemplate.Resources>
<LinearGradientBrush x:Key="Brush_NavButtonBorder0" StartPoint="0,0" EndPoint="0,1" >
<GradientStop Color="{StaticResource BorderColor}" Offset="0" />
<GradientStop Color="#FF383f47" Offset="1" />
</LinearGradientBrush>
</ControlTemplate.Resources>
<Grid>
<Border x:Name="outerBorder" CornerRadius="5" BorderThickness="1" BorderBrush="{StaticResource Brush_NavButtonBorder0}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True" />
<Border Margin="1" CornerRadius="4" BorderThickness="1" BorderBrush="{StaticResource Brush_NavButtonBorder4}" Background="Transparent" SnapsToDevicePixels="True">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Name="content"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<!--<Setter TargetName="outerBorder" Property="BorderBrush" Value="Gray" />-->
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetName="outerBorder"
Storyboard.TargetProperty="(Border.BorderBrush).(GradientBrush.GradientStops)[0].(GradientStop.Color)"
To="Gray"
Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetName="outerBorder"
Storyboard.TargetProperty="(Border.BorderBrush).(GradientBrush.GradientStops)[0].(GradientStop.Color)"
To="{StaticResource BorderColor}"
Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="{StaticResource Brush_NavButtonPressedBackground}" />
<Setter TargetName="content" Property="RenderTransform" >
<Setter.Value>
<TranslateTransform X="2.0" Y="2.0" />
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value="0.5" />
</Trigger>
<!--<Trigger Property="IsKeyboardFocused" Value="True">
<Setter Property="FocusVisualStyle" Value="{StaticResource MyFocusVisualStyle}" />
</Trigger>-->
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
This will mean that each button instance gets its own copy of the LinearGradientBrush, and your mouseover trigger animation is only affecting the one for the button that the mouse is over.
Again, there are a number of different ways to resolve this issue, but the code snippet above is the simplest I can think of given your current code.