can anyone check my code and tell me what's wrong with it?
This is the code i've been working on and i can't figure out why the mouseover event won't fire anymore after i clicked the button. please help, thanks!
UPDATE: I tried removing the IsPressed event, and somehow the code works perfectly, there is a conflict with the IsMouseover & IsPressed and i have no idea on how to fix it.
<Style x:Key="MediaControls" TargetType="{x:Type Button}">
<Setter Property="Focusable" Value="False"/>
<Setter Property="VerticalAlignment" Value="Bottom"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<ControlTemplate.Resources>
<Storyboard x:Key="FadeIn">
<DoubleAnimation Duration="0:0:0.15" Storyboard.TargetName="ImageContainer" Storyboard.TargetProperty="Opacity" To="0.8" />
</Storyboard>
<Storyboard x:Key="FadeOut">
<DoubleAnimation Duration="0:0:0.15" Storyboard.TargetName="ImageContainer" Storyboard.TargetProperty="Opacity" To="1" />
</Storyboard>
<Storyboard x:Key="ClickIn">
<DoubleAnimation Duration="0:0:0.20" Storyboard.TargetName="ImageContainer" Storyboard.TargetProperty="Opacity" To="0.5" />
</Storyboard>
<Storyboard x:Key="ClickOut">
<DoubleAnimation Duration="0:0:0.20" Storyboard.TargetName="ImageContainer" Storyboard.TargetProperty="Opacity" To="1" />
</Storyboard>
</ControlTemplate.Resources>
<Border x:Name="ImageContainer" Background="{TemplateBinding Background}" SnapsToDevicePixels="true">
<ContentPresenter x:Name="contentPresenter" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Trigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource FadeIn}" x:Name="FadeIn_BeginStoryboard" />
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard Storyboard="{StaticResource FadeOut}" x:Name="FadeOut_BeginStoryboard" />
</Trigger.ExitActions>
</Trigger>
<Trigger Property="IsPressed" Value="true">
<Trigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource ClickIn}" x:Name="ClickIn_BeginStoryboard" />
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard Storyboard="{StaticResource ClickOut}" x:Name="ClickOut_BeginStoryboard" />
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
You can set FillBehavior to Stop to make the animations stop covering the property when they are done.
Modify your resources section with the following code.
<ControlTemplate.Resources>
<Storyboard x:Key="FadeIn">
<DoubleAnimation Duration="0:0:0.15" Storyboard.TargetName="ImageContainer" Storyboard.TargetProperty="Opacity" To="0.8" />
</Storyboard>
<Storyboard x:Key="FadeOut">
<DoubleAnimation Duration="0:0:0.15" FillBehavior="Stop" Storyboard.TargetName="ImageContainer" Storyboard.TargetProperty="Opacity" To="1" />
</Storyboard>
<Storyboard x:Key="ClickIn">
<DoubleAnimation Duration="0:0:0.20" Storyboard.TargetName="ImageContainer" Storyboard.TargetProperty="Opacity" To="0.5" />
</Storyboard>
<Storyboard x:Key="ClickOut">
<DoubleAnimation Duration="0:0:0.20" FillBehavior="Stop" Storyboard.TargetName="ImageContainer" Storyboard.TargetProperty="Opacity" To="1" />
</Storyboard>
</ControlTemplate.Resources>
Simplify your ControlTemplate by using visual states:
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="Disabled"/>
<VisualState x:Name="MouseOver">
<Storyboard>
<DoubleAnimation Duration="0:0:0.15"
Storyboard.TargetProperty="Opacity" To="0.8" />
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<DoubleAnimation Duration="0:0:0.20"
Storyboard.TargetProperty="Opacity" To="0.5" />
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ContentPresenter x:Name="contentPresenter"
Focusable="False" RecognizesAccessKey="True"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Margin="{TemplateBinding Padding}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
</ControlTemplate>
Related
What I'm trying to do is set the background of control to a gradient when the ToggleButton its part of is enabled. This would be easy but this is WPF and for whatever reason will not let me use a LinearGradientBrush in the ColorAnimation.
All I'm looking for is just an alternative to accomplish something similar thing to what I've attempted to do below.
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border Background="DarkGray" Style="{StaticResource ToggleBrushOn}" x:Name="Pill">
<Border x:Name="Circle" Background="#FFFFFF" Width="22" Height="22" CornerRadius="22" Margin="35,5,5,5" HorizontalAlignment="Right"/>
<Border.Clip>
<RectangleGeometry Rect="0,0,65,32" RadiusX="15" RadiusY="32"/>
</Border.Clip>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Duration="0:0:0.1" Storyboard.TargetName="Pill" Storyboard.TargetProperty="(Control.Background)" To="{StaticResource tbGradient}"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Duration="0:0:0.1" Storyboard.TargetName="Pill" Storyboard.TargetProperty="(Control.Background)" To="DarkGray"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
When using <ColorAnimation Duration="0:0:0.1" Storyboard.TargetName="Pill" Storyboard.TargetProperty="(Control.Background)" To="{StaticResource tbo}"/> I receive the following error: ArgumentException: 'System.Windows.Media.LinearGradientBrush' is not a valid value for property 'To'.
tbGradient is supposed to be a Color:
<Color x:Key="tbGradient">Blue</Color>
You could then animate the background using the Trigger like this:
<Trigger Property="IsChecked" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Duration="0:0:0.1" Storyboard.TargetName="Pill" Storyboard.TargetProperty="(Control.Background).(SolidColorBrush.Color)" To="{StaticResource tbGradient}"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Duration="0:0:0.1" Storyboard.TargetName="Pill" Storyboard.TargetProperty="(Control.Background).(SolidColorBrush.Color)" To="DarkGray"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
If you want a gradient background, you could set the Background to a LinearGradientBrush and animate a GradientStop, e.g.:
<ToggleButton>
<ToggleButton.Resources>
<Color x:Key="tbGradient">Blue</Color>
</ToggleButton.Resources>
<ToggleButton.Template>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border x:Name="Pill">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="Yellow" Offset="0.0" />
<GradientStop x:Name="gs" Color="DarkGray" Offset="0.5" />
</LinearGradientBrush>
</Border.Background>
<Border x:Name="Circle" Background="#FFFFFF" Width="22" Height="22" CornerRadius="22" Margin="35,5,5,5" HorizontalAlignment="Right"/>
<Border.Clip>
<RectangleGeometry Rect="0,0,65,32" RadiusX="15" RadiusY="32"/>
</Border.Clip>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Duration="0:0:0.1" Storyboard.TargetName="gs" Storyboard.TargetProperty="Color" To="{StaticResource tbGradient}"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Duration="0:0:0.1" Storyboard.TargetName="gs" Storyboard.TargetProperty="Color" To="DarkGray"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</ToggleButton.Template>
</ToggleButton>
I have a custom button that I want to add animations to, but when I add the MouseLeave event and click the button while testing it fires the MouseLeave event instead of the MouseDown. When I remove the MouseLeave event it goes back to normal and fires the MouseDown event like expected.
<Style TargetType="{x:Type Button}" x:Key="CustomButton">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border CornerRadius="4" Background="Green">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Border.Triggers>
<EventTrigger RoutedEvent="Button.MouseDown">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
To="Red"
Duration="0:0:0.15" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="Button.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
To="Blue"
Duration="0:0:0.15" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="Button.MouseLeave">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
To="Green"
Duration="0:0:0.15" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Border.Triggers>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I have no idea why this happens so please help
You should handle the tunneling "Preview..." events where possible. In your case, handle the PreviewMouseDown event.
You should generally try to avoid event triggers to animate control states (or transitions to states). The recommended approach is to use the VisualStateManager to manage states.
Visit Microsoft Docs: Control Styles and Templates to learn about the defined states of every library control.
Your Style that uses the VisualStateManager to animate control state transitions (notice the cleaner look):
<Style TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="Border"
CornerRadius="4"
Background="Green">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualStateGroup.Transitions>
<VisualTransition From="MouseOver"
To="Normal"
GeneratedDuration="0:0:1.5" />
</VisualStateGroup.Transitions>
<VisualState x:Name="Normal" />
<VisualState x:Name="MouseOver">
<Storyboard>
<ColorAnimation Storyboard.TargetName="Border"
Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
To="Blue"
Duration="0:0:0.15" />
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ColorAnimation Storyboard.TargetName="Border"
Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
To="Red"
Duration="0:0:0.15" />
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Looking for easiest way to style button like so:
100% transparent, lookless, etc. The only visual is "X" which need to be drawn
MouseOver will color that "X" with different color.
What is the steps to come up with such control? I'm not sure how to approach it. The only way I know is to get template using Blend and then edit it by removing all elements, borders, etc. Is there any easier way?
The easiest way is to retemplate it, either by starting with an existing template or by hacking out a new one.
I think that it is definitely worth getting comfortable enough with templating that you can write a template like this one by hand.
Most of the time it is quite straight forward. The most complicated part is getting the visual states. You can read more about the VisualStateManager class here.
Here is an example of what a template could look like for your scenario:
<Grid x:Name="LayoutRoot" Background="White">
<Grid.Resources>
<ControlTemplate x:Key="XButtonTemplate">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="MouseOver">
<Storyboard>
<ColorAnimation Storyboard.TargetName="textblock"
Storyboard.TargetProperty="(Foreground).(Color)" To="Red"
Duration="0:0:0.2" />
</Storyboard>
</VisualState>
<VisualState x:Name="Normal">
<Storyboard>
<ColorAnimation Storyboard.TargetName="textblock"
Storyboard.TargetProperty="(Foreground).(Color)" To="Black"
Duration="0:0:0.2" />
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<TextBlock x:Name="textblock" HorizontalAlignment="Center" VerticalAlignment="Center" Text="X" />
</Grid>
</ControlTemplate>
</Grid.Resources>
<StackPanel>
<Button Height="23" Width="23" Template="{StaticResource XButtonTemplate}" />
</StackPanel>
</Grid>
i can help you when user press
in app.xaml
add
<Style x:Key="btnStylePress" TargetType="Button">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="{StaticResource PhoneForegroundBrush}"/>
<Setter Property="Foreground" Value="{StaticResource PhoneForegroundBrush}"/>
<Setter Property="BorderThickness" Value="{StaticResource PhoneBorderThickness}"/>
<Setter Property="FontFamily" Value="{StaticResource PhoneFontFamilySemiBold}"/>
<Setter Property="FontSize" Value="{StaticResource PhoneFontSizeMediumLarge}"/>
<Setter Property="Padding" Value="10,3,10,5"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid Background="Transparent">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver"/>
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentContainer">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneBackgroundBrush}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="ButtonBackground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneForegroundBrush}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="ButtonBackground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneForegroundBrush}"/>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleY)" Storyboard.TargetName="ContentContainer" />
<DoubleAnimation Duration="0" To="0" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)" Storyboard.TargetName="ContentContainer" />
<DoubleAnimation Duration="0" To="-0.652" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleX)" Storyboard.TargetName="ContentContainer"/>
<DoubleAnimation Duration="0" To="-76" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="ContentContainer"/>
<DoubleAnimation Duration="0" To="0.826" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleX)" Storyboard.TargetName="ButtonBackground" />
<DoubleAnimation Duration="0" To="-8" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="ButtonBackground"/>
<DoubleAnimation Duration="0" To="0.552" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleY)" Storyboard.TargetName="ButtonBackground" />
<DoubleAnimation Duration="0" To="-24" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)" Storyboard.TargetName="ButtonBackground" />
<DoubleAnimation Duration="0" To="0" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="ButtonBackground" />
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentContainer">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneDisabledBrush}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="ButtonBackground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneDisabledBrush}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="ButtonBackground">
<DiscreteObjectKeyFrame KeyTime="0" Value="Transparent"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border x:Name="ButtonBackground" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" CornerRadius="0" Margin="{StaticResource PhoneTouchTargetOverhang}" RenderTransformOrigin="0.5,0.5">
<Border.RenderTransform>
<CompositeTransform/>
</Border.RenderTransform>
<ContentControl x:Name="ContentContainer" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Foreground="{TemplateBinding Foreground}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" Padding="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" RenderTransformOrigin="0.5,0.5">
<ContentControl.RenderTransform>
<CompositeTransform/>
</ContentControl.RenderTransform>
</ContentControl>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
and any button you want to get that style
<Button **Style="{StaticResource btnStylePress}"** Grid.Row="1" Height="266" HorizontalAlignment="Left" Margin="252,419,0,0" Name="BtnStore" VerticalAlignment="Top" Width="154" Click="BtnStore_Click" BorderThickness="0" Background="{x:Null}" />
Been trying to make a tabcontrol with some animation when changing tabs but it keeps giving me grief and refusing to let me put the animation in any useful place unless it's in the same XAML window file as the control itself (the style resides in a DLL file from which other styles work). Here's my style:
<Style x:Key="AnimatedTabControl" TargetType="{x:Type TabControl}">
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Background" Value="White" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Border>
<TabPanel
IsItemsHost="True">
</TabPanel>
</Border>
<Border BorderThickness="0"
Grid.Row="1"
BorderBrush="White"
Background="White">
<ContentPresenter x:Name="TabControlContent" ContentSource="SelectedContent" Margin="0" />
</Border>
</Grid>
<ControlTemplate.Resources>
<Storyboard x:Key="TabSelectionChangedStoryboard">
<DoubleAnimation Storyboard.TargetName="TabControlContent"
Storyboard.TargetProperty="Opacity"
To="100"
From="0"
FillBehavior="HoldEnd"
Duration="0:0:30.0" />
</Storyboard>
</ControlTemplate.Resources>
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="SelectionChanged">
<BeginStoryboard Storyboard="{StaticResource TabSelectionChangedStoryboard}" />
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
This results in 'TabControlContent' name cannot be found in the name scope of 'System.Windows.Controls.ControlTemplate'
I've also tried to move the animation to the beginning of the file, which results in the same error. If I put it after the style, the storyboard can't find it. Is there any way around this?
Solution:
use Storyboard.Target instead of Storyboard.TargetName in combination with {Binding ElementName=TabControlContent.
replace
<DoubleAnimation
Storyboard.TargetName="TabControlContent"
Storyboard.TargetProperty="Opacity"
To="100"
From="0"
FillBehavior="HoldEnd"
Duration="0:0:30.0" />
with
<DoubleAnimation
Storyboard.Target="{Binding ElementName=TabControlContent}"
Storyboard.TargetProperty="Opacity"
To="100"
From="0"
FillBehavior="HoldEnd"
Duration="0:0:30.0" />
I search on web a lot but did not found appropriate answer... and after four days try Finally completed this way...
<ControlTemplate x:Key="GeneralButton" TargetType="{x:Type Button}">
<Grid>
<Border Background="{StaticResource ButtonGeneral}"
VerticalAlignment="Stretch" CornerRadius="6" HorizontalAlignment="Stretch"/>
<Border x:Name="BorderFocused" Opacity="0" Background="{StaticResource ButtonFocused}"
VerticalAlignment="Stretch" CornerRadius="6" HorizontalAlignment="Stretch"/>
<Border x:Name="BorderPressed" Opacity="0" Background="Purple"
VerticalAlignment="Stretch" CornerRadius="6" HorizontalAlignment="Stretch"/>
<Border x:Name="BorderDisabled" Opacity="0" Background="{StaticResource ButtonDisabled}"
VerticalAlignment="Stretch" CornerRadius="6" HorizontalAlignment="Stretch"/>
<ContentPresenter VerticalAlignment="Center"
HorizontalAlignment="Center" x:Name="MainContent" Margin="20,5" >
<TextElement.Foreground>
<SolidColorBrush Color="White"></SolidColorBrush>
</TextElement.Foreground>
<TextElement.FontSize>
16
</TextElement.FontSize>
</ContentPresenter>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsKeyboardFocused" Value="true">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="BorderFocused" Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0.01"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="BorderFocused" Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:0.4"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="BorderFocused" Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0.01"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="BorderFocused" Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:0.4"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="BorderPressed" Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0.01"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="BorderPressed" Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:0.5"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="BorderDisabled" Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="BorderDisabled" Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:0.2"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
I solved the problem using the "VisualStateManager", at the following link you will find a brief explanation of the differences between "VisualStateManager" and "Triggers".
https://stackoverflow.com/a/41030110/13037386
This shows how the graphic states are detached from triggers.
I have the ListBox ItemContainerStyle below. It simply provides for a nice fade-in, and slide out when items are added or removed from the ItemsSource respectively; it works fine.
The problem occurs when I put my list box into a TabControl from the SL toolkit. When I load some items into my listbox, then flip to another tab, then flip back, if I remove an item, I see the animation occur, then right as it's about to finish, I get the following NullReferenceException exception:
at
System.Windows.Controls.ItemContainerGenerator.LayoutStatesManager._layoutStatesGroups_CurrentStateChanged(Object
sender, VisualStateChangedEventArgs e)
at
MS.Internal.CoreInvokeHandler.InvokeEventHandler(Int32
typeIndex, Delegate handlerDelegate,
Object sender, Object args) at
MS.Internal.JoltHelper.FireEvent(IntPtr
unmanagedObj, IntPtr unmanagedObjArgs,
Int32 argsTypeIndex, Int32
actualArgsTypeIndex, String eventName)
To make matters worse, this only happens when I use a custom ItemsPanel, ie a horizontal StackPanel instead of the default VirtualizingPanel.
Here's the complete Template:
<Style x:Key="ListBoxStyleAnimatedAddAndRemove" TargetType="ListBoxItem">
<Setter Property="Padding" Value="3"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="VerticalContentAlignment" Value="Top"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="TabNavigation" Value="Local"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Grid Background="{TemplateBinding Background}" x:Name="rootGridElement">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="LayoutStates">
<VisualState x:Name="AfterLoaded">
<Storyboard>
<DoubleAnimation
Duration="00:00:1"
From="0" To="1"
Storyboard.TargetName="rootGridElement"
Storyboard.TargetProperty="Opacity" />
</Storyboard>
</VisualState>
<VisualState x:Name="BeforeUnloaded" />
<VisualStateGroup.Transitions>
<VisualTransition From="AfterLoaded" To="BeforeUnload" GeneratedDuration="0:0:0.5">
<Storyboard>
<DoubleAnimation
Duration="00:00:0.25"
By="235"
Storyboard.TargetName="contentProjection"
Storyboard.TargetProperty="GlobalOffsetY" />
</Storyboard>
</VisualTransition>
</VisualStateGroup.Transitions>
</VisualStateGroup>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="MouseOver">
<Storyboard>
<DoubleAnimation Duration="0" To=".35" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="fillColor"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<DoubleAnimation Duration="0" To=".55" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="contentPresenter"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="SelectionStates">
<VisualState x:Name="Unselected"/>
<VisualState x:Name="Selected">
<Storyboard>
<DoubleAnimation Duration="0" To=".75" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="fillColor2"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="FocusStates">
<VisualState x:Name="Focused">
<Storyboard>
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetProperty="Visibility" Storyboard.TargetName="FocusVisualElement">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Unfocused"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Rectangle x:Name="fillColor" Fill="#FFBADDE9" IsHitTestVisible="False" Opacity="0" RadiusY="1" RadiusX="1"/>
<Rectangle x:Name="fillColor2" Fill="#FFBADDE9" IsHitTestVisible="False" Opacity="0" RadiusY="1" RadiusX="1"/>
<ContentPresenter x:Name="contentPresenter" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}">
<ContentPresenter.Projection>
<PlaneProjection x:Name="contentProjection">
</PlaneProjection>
</ContentPresenter.Projection>
</ContentPresenter>
<Rectangle x:Name="FocusVisualElement" RadiusY="1" RadiusX="1" Stroke="#FF6DBDD1" StrokeThickness="1" Visibility="Collapsed"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>