Animate button background color in XAML - c#

I new to WPF and XAML, so I have ResourceDictionary (one button for now):
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="ButtonProduct" TargetType="Button">
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Name="Border"
CornerRadius="0"
BorderThickness="0"
Focusable="False"
BorderBrush="Transparent" Background="White">
<ContentPresenter Margin="2" HorizontalAlignment="Center" VerticalAlignment="Center" RecognizesAccessKey="True"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" Value="#52b0ca"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
On hover the color of the button changes, but how can I make change in fade in and out, for smooth transition of the color?

You can use EventTrigger to start ColorAnimation on MouseEnter and MouseLeave:
<ControlTemplate TargetType="{x:Type Button}">
<Border Name="Border" CornerRadius="0" BorderThickness="0" Focusable="False" BorderBrush="Transparent" Background="White">
<ContentPresenter Margin="2" HorizontalAlignment="Center" VerticalAlignment="Center" RecognizesAccessKey="True"/>
</Border>
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="MouseEnter">
<BeginStoryboard>
<Storyboard>
<ColorAnimation From="White" To="#52b0ca" Duration="0:0:1" Storyboard.TargetName="Border" Storyboard.TargetProperty="Background.Color"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="MouseLeave">
<BeginStoryboard>
<Storyboard>
<ColorAnimation From="#52b0ca" To="White" Duration="0:0:1" Storyboard.TargetName="Border" Storyboard.TargetProperty="Background.Color"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>

Related

C# implementation Button Animation shows weird behaviour [duplicate]

I am currently working on a C# WPF project and I am trying to make my custom style buttons.
What I want to have to happen, is when the mouse hovers over the button, it slightly increases in size as an animation, then when the mouse leaves the button, the animation decreases the size of the button to the original size.
Below is my ControlTemplate that I've created for my button. No errors are thrown but nothing happens either.
<Application.Resources>
<Style x:Key="RoundCorner" TargetType="{x:Type Button}">
<Setter Property="Foreground" Value="White" />
<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}">
<Grid Name="ButtonGrid">
<Border x:Name="border" CornerRadius="8" BorderBrush="White" BorderThickness="2">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"
TextElement.FontWeight="Bold"></ContentPresenter>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="BorderBrush" TargetName="border" Value="Blue"/>
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="ButtonGrid"
Storyboard.TargetProperty="(Rectangle.RenderTransform).(ScaleTransform.ScaleX)"
To="0.95" Duration="0:0:0.05" />
<DoubleAnimation
Storyboard.TargetName="ButtonGrid"
Storyboard.TargetProperty="(Rectangle.RenderTransform).(ScaleTransform.ScaleY)"
To="0.95" Duration="0:0:0.05" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="ButtonGrid"
Storyboard.TargetProperty="(Rectangle.RenderTransform).(ScaleTransform.ScaleX)"
To="1.08" Duration="0:0:0.05" />
<DoubleAnimation
Storyboard.TargetName="ButtonGrid"
Storyboard.TargetProperty="(Rectangle.RenderTransform).(ScaleTransform.ScaleY)"
To="1.08" Duration="0:0:0.05" />
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" TargetName="ButtonGrid" Value="0.25"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Application.Resources>
</Application>
Thanks for any help you can provide
You have couple of problems with your code:
1) You are trying to animate Rectangle.RenderTransform properties and there is no Rectangle in your ControlTemplate. RenderTransform is a dependency property on UIElement. So, you should remove Rectangle
2) Also, There is no RenderTransform applied to your Grid.
3) After fixing above two items, if you try you get continuous animation (Button expanding/shrinking in size), to fix this set Background property Grid to Transparent, so that Grid participates in hit testing and respond to Mouse overs.
Update your style XAML to the following and it will work:
<Style x:Key="RoundCorner" TargetType="{x:Type Button}">
<Setter Property="Foreground" Value="White"/>
<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}">
<Grid Name="ButtonGrid" Background="Transparent">
<Border
x:Name="border"
BorderBrush="White"
BorderThickness="2"
CornerRadius="8">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" TextElement.FontWeight="Bold">
</ContentPresenter>
</Border>
<Grid.RenderTransform>
<ScaleTransform />
</Grid.RenderTransform>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="BorderBrush" Value="Blue"/>
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Duration="0:0:0.05"
Storyboard.TargetName="ButtonGrid"
Storyboard.TargetProperty="(RenderTransform).(ScaleTransform.ScaleX)"
To="0.95"/>
<DoubleAnimation
Duration="0:0:0.05"
Storyboard.TargetName="ButtonGrid"
Storyboard.TargetProperty="(RenderTransform).(ScaleTransform.ScaleY)"
To="0.95"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Duration="0:0:0.05"
Storyboard.TargetName="ButtonGrid"
Storyboard.TargetProperty="(RenderTransform).(ScaleTransform.ScaleX)"
To="1.08"/>
<DoubleAnimation
Duration="0:0:0.05"
Storyboard.TargetName="ButtonGrid"
Storyboard.TargetProperty="(RenderTransform).(ScaleTransform.ScaleY)"
To="1.08"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="ButtonGrid" Property="Opacity" Value="0.25"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Another thing, instead of using Trigger.EnterActions and Trigger.ExitActions, you could use VisualStateManager to achieve the same result. Using VisualStateManager is much more easier than Trigger.EnterActions and ExitActions.
Below is the code with VisualStateManager used to do the animations:
<Style x:Key="RoundCorner" TargetType="{x:Type Button}">
<Setter Property="Foreground" Value="White"/>
<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}">
<Grid Name="ButtonGrid" Background="Transparent">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0:0:0.05" To="MouseOver"/>
<VisualTransition GeneratedDuration="0:0:0.05" To="Normal"/>
</VisualStateGroup.Transitions>
<VisualStateGroup.States>
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver">
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="ButtonGrid"
Storyboard.TargetProperty="(RenderTransform).(ScaleTransform.ScaleX)"
To="0.95"/>
<DoubleAnimation
Storyboard.TargetName="ButtonGrid"
Storyboard.TargetProperty="(RenderTransform).(ScaleTransform.ScaleY)"
To="0.95"/>
</Storyboard>
</VisualState>
</VisualStateGroup.States>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border
x:Name="border"
BorderBrush="White"
BorderThickness="2"
CornerRadius="8">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" TextElement.FontWeight="Bold">
</ContentPresenter>
</Border>
<Grid.RenderTransform>
<ScaleTransform/>
</Grid.RenderTransform>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="BorderBrush" Value="Blue"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="ButtonGrid" Property="Opacity" Value="0.25"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Animating SolidColorBrush in Background

I am trying to create a simple button style, that will change the opacity of the background from 0.0 to 1.0 on mouse over (and vice versa). I am creating a template for said button and I am binding all the properties in the template. It all works properly except the SolidColorBrush in background, that I can not bind to the template binding. I've seen some mentions of TemplateBinding not being the right one due to contexts, but I am not able to find another solution. I suspect, there might be a problem of Background being a Brush and I need just a Color component of that brush, but I am not able to obtain it.
The obvious override is to create two template styles with two different colors (which works), but I would like to avoid such hard-coding and copy-paste. What I would like to have is an option to specify Background property on Button, that would be used in SolidColorBrush and then the opacity would do the rest.
<Style TargetType="{x:Type Button}" x:Key="WindowButtonStyle">
<Setter Property="Width" Value="46" />
<Setter Property="Height" Value="32" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
<Border.Background>
<SolidColorBrush x:Name="ButtonBackgroundBrush" Color="???" Opacity="0.0" />
</Border.Background>
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}" />
</Border>
<ControlTemplate.Resources>
<Storyboard x:Key="MouseOverAnimation">
<DoubleAnimation Storyboard.TargetName="ButtonBackgroundBrush" Storyboard.TargetProperty="Opacity" To="1.0" Duration="0:0:0.15" />
</Storyboard>
<Storyboard x:Key="MouseOutAnimation">
<DoubleAnimation Storyboard.TargetName="ButtonBackgroundBrush" Storyboard.TargetProperty="Opacity" To="0.0" Duration="0:0:0.15" />
</Storyboard>
</ControlTemplate.Resources>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Trigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource MouseOverAnimation}" />
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard Storyboard="{StaticResource MouseOutAnimation}" />
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Then, the button is used like this:
<Button x:Name="MinimizeButton" Style="{StaticResource WindowButtonStyle}" Click="MinimizeButton_Click" Background="Green">
<Image Source="../Resources/WindowButtons/Images/win-minimize.png" Width="12" Height="12"></Image>
</Button>
Added Background="Green" property setting to test it, but did not worked.
You could use a TemplateBinding to bind the Background property of the Border to the Background of the Button and then animate the Opacity property of the SolidColorBrush like this:
<Style TargetType="{x:Type Button}" x:Key="WindowButtonStyle">
<Setter Property="Width" Value="46" />
<Setter Property="Height" Value="32" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}" />
</Border>
<ControlTemplate.Resources>
<Storyboard x:Key="MouseOverAnimation">
<DoubleAnimation Storyboard.TargetName="border" Storyboard.TargetProperty="Background.(SolidColorBrush.Opacity)" To="1.0" Duration="0:0:0.15" />
</Storyboard>
<Storyboard x:Key="MouseOutAnimation">
<DoubleAnimation Storyboard.TargetName="border" Storyboard.TargetProperty="Background.(SolidColorBrush.Opacity)" To="0.0" Duration="0:0:0.15" />
</Storyboard>
</ControlTemplate.Resources>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Trigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource MouseOverAnimation}" />
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard Storyboard="{StaticResource MouseOutAnimation}" />
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Answering my own, as always - you figure out the solution just after you post on S/O. So I hope it will help someone:
...
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
<Border.Background>
<!-- ReSharper disable once Xaml.BindingWithContextNotResolved -->
<SolidColorBrush x:Name="ButtonBackgroundBrush" Color="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Background.Color}" Opacity="0.0" />
</Border.Background>
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}" />
</Border>
...
I've included the ReSharper disable as well, because the warning form ReSharper was what kept me from trying this one - and desperation forced me to try it anyway.

WPF: button control template not firing click event

I am making my own costumed button, which has a label in it. For some reason, my button doesn't react to the 'click' event, and the click function doesn't lunch. why?
here is my button style xaml code:
<Style x:Key="MyMenuButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Background" Value="#AF4EB4EC"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Margin" Value="0,0,5,0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid >
<Rectangle Fill="{TemplateBinding Background}" StrokeThickness="0" MinWidth="{Binding ElementName=lblCnt,Path=Width}"/>
<Label Name="lblCnt" Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center"
Foreground="{TemplateBinding Foreground}" FontSize="{TemplateBinding FontSize}" Background="{TemplateBinding Background}"
Height="auto" Width="auto"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Background" Value="White"/>
</Trigger>
<EventTrigger RoutedEvent="UIElement.MouseEnter">
<BeginStoryboard >
<Storyboard>
<!--<DoubleAnimation Storyboard.TargetProperty="Width"
Duration="0:0:0.200" By="30"/>-->
<DoubleAnimation Storyboard.TargetProperty="FontSize"
Duration="0:0:0.200"
From="12" To="22"/>
<ColorAnimation Storyboard.TargetProperty="(Control.Background).(SolidColorBrush.Color)"
Duration="0:0:0.200"
From="#AF4EB4EC" To="White"/>
<ColorAnimation Storyboard.TargetProperty="(Control.Foreground).(SolidColorBrush.Color)"
Duration="0:0:0.200"
From="White" To="#AF4EB4EC"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="UIElement.MouseLeave">
<BeginStoryboard>
<Storyboard >
<!--<DoubleAnimation Storyboard.TargetProperty="Width"
Duration="0:0:0.100"
By="-30"/>-->
<DoubleAnimation Storyboard.TargetProperty="FontSize"
Duration="0:0:0.100"
From="22" To="12"/>
<ColorAnimation Storyboard.TargetProperty="(Control.Background).(SolidColorBrush.Color)"
Duration="0:0:0.100"
From="White"
To="#AF4EB4EC"/>
<ColorAnimation Storyboard.TargetProperty="(Control.Foreground).(SolidColorBrush.Color)"
Duration="0:0:0.100"
From="#AF4EB4EC"
To="White"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
and this is the complete xaml code:
<Window x:Class="FMS_Csharp_GUI.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="File Indexer" Height="552" Width="864" Icon="magna-folder-icon.ico">
<Window.CommandBindings>
<CommandBinding Command="New" CanExecute="CanExeNewRepo" Executed="ClickNewRepo"/>
<CommandBinding Command="Delete" CanExecute="CanExeNewRepo" Executed="ClickDeleteRepo"/>
</Window.CommandBindings>
<Window.Resources>
<StackPanel x:Key="documentStackPanelStyle" Orientation="Horizontal" >
<Image Source="Images/openDoc.ico" Width="32" Height="32"/>
<Label Content="" VerticalAlignment="Center"/>
</StackPanel>
<Style x:Key="MyMenuButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Background" Value="#AF4EB4EC"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Margin" Value="0,0,5,0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid >
<Rectangle Fill="{TemplateBinding Background}" StrokeThickness="0" MinWidth="{Binding ElementName=lblCnt,Path=Width}"/>
<Label Name="lblCnt" Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center"
Foreground="{TemplateBinding Foreground}" FontSize="{TemplateBinding FontSize}" Background="{TemplateBinding Background}"
Height="auto" Width="auto"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Background" Value="White"/>
</Trigger>
<EventTrigger RoutedEvent="UIElement.MouseEnter">
<BeginStoryboard >
<Storyboard>
<!--<DoubleAnimation Storyboard.TargetProperty="Width"
Duration="0:0:0.200" By="30"/>-->
<DoubleAnimation Storyboard.TargetProperty="FontSize"
Duration="0:0:0.200"
From="12" To="22"/>
<ColorAnimation Storyboard.TargetProperty="(Control.Background).(SolidColorBrush.Color)"
Duration="0:0:0.200"
From="#AF4EB4EC" To="White"/>
<ColorAnimation Storyboard.TargetProperty="(Control.Foreground).(SolidColorBrush.Color)"
Duration="0:0:0.200"
From="White" To="#AF4EB4EC"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="UIElement.MouseLeave">
<BeginStoryboard>
<Storyboard >
<!--<DoubleAnimation Storyboard.TargetProperty="Width"
Duration="0:0:0.100"
By="-30"/>-->
<DoubleAnimation Storyboard.TargetProperty="FontSize"
Duration="0:0:0.100"
From="22" To="12"/>
<ColorAnimation Storyboard.TargetProperty="(Control.Background).(SolidColorBrush.Color)"
Duration="0:0:0.100"
From="White"
To="#AF4EB4EC"/>
<ColorAnimation Storyboard.TargetProperty="(Control.Foreground).(SolidColorBrush.Color)"
Duration="0:0:0.100"
From="#AF4EB4EC"
To="White"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<Grid x:Name="grdContents" Margin="0,23,0,76">
<Grid Name="grdUserInfo" HorizontalAlignment="Right" Height="50" VerticalAlignment="Top" Width="189" Margin="0,-18,0,0">
<Image Name="imgUser" Source="Images/notloggedin.jpg" HorizontalAlignment="Right" Height="49.667" VerticalAlignment="Top"/>
<Label Name="lblUser" Content="you are not logged in!" Margin="0,0,54.667,0" HorizontalAlignment="Right" Width="134.333" Height="49.667" VerticalAlignment="Top"/>
</Grid>
<StackPanel Name="stkpMyStyledMenu" Height="47" Margin="0,10,0,0" Background="#FF4EA2EC" Orientation="Horizontal" VerticalAlignment="Top" HorizontalAlignment="Left">
<StackPanel.Resources>
<Style BasedOn="{StaticResource MyMenuButtonStyle}" TargetType="Button"/>
</StackPanel.Resources>
<Button Content="New Repo" Click="myMenuNewRepo"/>
<Button Content="Open Repo" Click="MyMenuClickOpenRepo" />
<Button Content="Login" Click="MyMenuClickLogin"/>
<Button Content="Exit" Click="MyMenuClickExit"/>
</StackPanel>
<GroupBox Header="Input" Name="grpInput" HorizontalAlignment="Left" Margin="145,0,0,120" VerticalAlignment="Bottom" RenderTransformOrigin="0.352,-0.304" Height="185" Width="290">
</GroupBox>
<Button Content="Button" HorizontalAlignment="Left" Margin="205,70,0,0" VerticalAlignment="Top" Width="75" Click="MyMenuClickNewRepo"/>
<Button Content="Button" Click="MyMenuClickOpenRepo" HorizontalAlignment="Left" Margin="285,70,0,0" VerticalAlignment="Top" Width="75"/>
</Grid>
<ListBox Name="lstMessages" Height="61" VerticalAlignment="Bottom"/>
</Grid>
Use Snoop's events tab to determine which control is handling your click.
Could it be you set something in a way that the label gets the click? You could check binding some handler-code to the Click event of the label.

Validation.HasError and custom ToolTip

I'm setting extra ToolTip for a field with errors in ResourceDictionary
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
I also defined special style for this tooltip, which simulate the one on red triangle in right upper corner
<Style TargetType="ToolTip">
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="HasDropShadow" Value="True"/>
<Setter Property="Placement" Value="Right"/>
<Setter Property="HorizontalOffset" Value="5"/>
<Setter Property="Foreground" Value="White" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToolTip">
<Border Name="Border"
Background="Red"
Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}">
<ContentPresenter Margin="5 2 5 3"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="Opened">
<BeginStoryboard>
<Storyboard TargetProperty="HorizontalOffset">
<DoubleAnimation From="0" To="5" Duration="0:0:0.1" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Everything works, but now ALL ToolTips have this style.
Is it possible to achieve that ToolTip style take his part only if Validation.HasError occurs? I can as x:Key, but how to apply that to Style.Triggers part?
Because I have this ToolTip defined also on other controls I wouldn't like to copy all this code multiple times, but if only that is a solution I will do so :(
After another couple of hours of Googling I try the solution provided here
https://social.msdn.microsoft.com/Forums/vstudio/en-US/10d2ecbf-9e6e-4414-b57e-79dd02e0944e/changing-style-of-tooltip-in-textbox
and it works!
A created ToolTip style
<ToolTip x:Key="ErrorToolTip"
Placement="Right"
Background="Red"
Foreground="White"
BorderThickness="0"
DataContext="{Binding Path=PlacementTarget, RelativeSource={RelativeSource Self}}">
<ToolTip.Content>
<Binding Path="(Validation.Errors)[0].ErrorContent"/>
</ToolTip.Content>
<ToolTip.Triggers>
<EventTrigger RoutedEvent="ToolTip.Opened">
<BeginStoryboard>
<Storyboard TargetProperty="HorizontalOffset">
<DoubleAnimation From="0" To="5" Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ToolTip.Triggers>
</ToolTip>
and changed Style.Triggers to
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip" Value="{StaticResource ErrorToolTip}" />
</Trigger>
</Style.Triggers>
Need to do some more styling, but it's OK for now.
You can set the property Validation.ErrorTemplate on the TextBox style:
<Style TargetType="{x:Type TextBox}">
<Setter Property="Validation.ErrorTemplate"
Value="{StaticResource ValidationTemplate}" />
<Style.Triggers>
<Trigger Property="Validation.HasError"
Value="true">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
However, this way you can't work with a ToolTip style, but you have to work with a template and a x:Key.
<ControlTemplate x:Key="ValidationTemplate">
<Border Name="Border"
Background="Red"
Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}">
<ContentPresenter Margin="5 2 5 3"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="Opened">
<BeginStoryboard>
<Storyboard TargetProperty="HorizontalOffset">
<DoubleAnimation From="0" To="5" Duration="0:0:0.1" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>

WPF style/control template reuse

I'm new to WPF, and I would like to know how to reuse some annoying xaml I have to avoid duplicating.
<Button Cursor="Hand" HorizontalAlignment="Left" Margin="0,0,0,0" x:Name="MyButton" Style="{StaticResource ButtonTemplate}" Width="286" Content="hi!" Focusable="False" IsTabStop="False"/>
<Button Cursor="Hand" HorizontalAlignment="Left" Margin="0,0,0,0" x:Name="MyButton2" Style="{StaticResource ButtonTemplate}" Width="286" Content="hi 2!" Focusable="False" IsTabStop="False"/>
I'd really like to use something like this template:
<Style TargetType="{x:Type Button}" x:Key="ButtonTemplate">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid x:Name="btGrid">
<Path Cursor="Hand" HorizontalAlignment="Left" Stretch="Fill" Stroke="{x:Null}" Opacity="0" x:Name="path"/>
<ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" RecognizesAccessKey="True" Visibility="Hidden" HorizontalAlignment="Left" Margin="0,0,0,0" VerticalAlignment="Top"/>
</Grid>
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="Button.PreviewMouseLeftButtonDown">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard SlipBehavior="Slip" BeginTime="00:00:00">
<MediaTimeline Source="{Binding StringFormat={}, Path=Name}" Storyboard.TargetName="{Binding StringFormat={}_wma, Path=Name}"/>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="{Binding StringFormat=key{}, Path=Name}" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>
Visible
</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="Button.PreviewMouseLeftButtonUp">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="{Binding StringFormat=key{}, Path=Name}" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>
Hidden
</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<Trigger Property="IsFocused" Value="True"/>
<Trigger Property="IsDefaulted" Value="True"/>
<Trigger Property="IsMouseOver" Value="True"/>
<Trigger Property="IsPressed" Value="True"/>
<Trigger Property="IsEnabled" Value="False"/>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And I'd like the {Binding StringFormat={}, Path=Name} to point button's name, e.g. "MyButton", "MyButton2", etc.
When I run this code I get the error "Cannot freeze this Storyboard timeline tree for use across threads." :/ I understand this is because I use binding in a storyboard, correct? I don't know what to do to make this work.
Also, I'd like to make the ToggleVisibility of the image a template as well, that accepts once "Visible" and once "Hidden" values.
Thanks in advance!
You could always define properties other than Template in your style too.
<Style TargetType="{x:Type Button}"
x:Key="ButtonTemplate">
<Setter Property="Cursor" Value="Hand" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="Margin" Value="0,0,0,0" />
<Setter Property="Width" Value="286" />
<Setter Property="Focusable" Value="False" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
...
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Which makes your code look like
<Button x:Name="MyButton" Style="{StaticResource ButtonTemplate}" Content="hi!" />
<Button x:Name="MyButton2" Style="{StaticResource ButtonTemplate}" Content="hi 2!" />
Yeah creating a style with target type to as button would do the trick.
Tip:It is always a good practice to write all the styling informations such as border, background, templates, etc., under the resource section of your code and apply them on the controls. It'll give good readability.
HTH :)

Categories