I have a strange behavior of a storyboard animation inside a Button.
I Adjusted an existing Button style already used in my program, to display an animation to notify the user for the action in progress: some new buttons activate in theirs specific click event a long time running sequence (10 seconds). I though to add the animation directly in the btnStyle.
The buttonClick event start a method in which in the first line I Set an attachedProperty of the button to start the animation and in the last line the attachedProperty is reset.
The strange behaviour is that the animation NORMALLY doesn't show: it is displayed only in the case if in the middle of the buttonClick event method there is a System.Windows.MessageBox to ask confirmation to the user.
To Debug the situation, in the code where I activated the Animation, I added the Mouse.OverrideCursor = Cursors.Wait
: the mouse changes for every buttonClick event (with or without the MEssageBox).
To add tests, I separated the buttonClick event code in a specific method and i started it also with a Dispatcher.BeginInvoke.
No way at all to see the Animation.
Thanks in advance....
This is the scenario:
1) in a Windows, i have some buttons declared as follow:
<Button Grid.Row="0" Grid.Column="1" Style="{DynamicResource btnStyle}" Name="btnCashQ_Report" Content="Stampa situazione" />
2) in a resource file i declared the btnStyle:
<!-- STYLE BUTTON #START -->
<Style x:Key="btnStyle" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="OuterBorder"
CornerRadius="3"
Background="{DynamicResource ButtonGradient}">
<Border
x:Name="InnerBorder"
CornerRadius="3"
Background="{DynamicResource ButtonUpGradient}"
Padding="{TemplateBinding Padding}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="12*" />
</Grid.ColumnDefinitions>
<ContentPresenter
x:Name="ContentSite"
Grid.Column="0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
>
<!-- $HELP: http://stackoverflow.com/questions/3970285/wpf-4-contentpresenter-textwrapping-style-is-not-applied-to-implicitedly-generat -->
<ContentPresenter.Resources>
<Style TargetType="{x:Type TextBlock}" >
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="TextWrapping" Value="Wrap"/>
<Setter Property="TextAlignment" Value="Center"/>
</Style>
</ContentPresenter.Resources>
</ContentPresenter>
<local:LoadingPanelSopra_6_12
x:Name="Animation"
Grid.Column="0"
AnimationEnable="{Binding Path=(buttonExt:WpfButtonExtensionsMethods.AnimationEnabled), RelativeSource={RelativeSource TemplatedParent}}"
/>
</Grid>
</Border>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsPressed" Value="true">
<Setter TargetName="InnerBorder" Property="Background" Value="{DynamicResource ButtonDownGradient}" />
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter TargetName="InnerBorder" Property="Background" Value="{DynamicResource ButtonDisabledGradient}" />
<Setter Property="BorderBrush" Value="Silver" />
<Setter Property="Foreground" Value="SlateGray" />
<Setter Property="Opacity" Value="0.5" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="buttonExt:WpfButtonExtensionsMethods.AnimationEnabled" Value="false"/>
<Setter Property="Foreground" Value="MidnightBlue" />
<Setter Property="FontFamily" Value="Segoe Black" />
<Setter Property="FontSize" Value="16px" />
<Setter Property="Margin" Value="5,5,5,5" />
<Setter Property="MinHeight" Value="25" />
<Setter Property="MaxHeight" Value="50" />
<Setter Property="MaxWidth" Value="250" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
</Style>
In the btnStyle
, you may find that the button contains a Grid
to arrange both the ContentPresenter
to arrange the TextBox Caption and a LoadingPanelSopra_6_12
: this last is a my custom UserControl which draw an arc with small square blocks using a StoryBoard Animation.
The animation is turned on by the attached property:
AnimationEnable="{Binding Path=(buttonExt:WpfButtonExtensionsMethods.AnimationEnabled), RelativeSource={RelativeSource TemplatedParent}}"
Here following, the usercontrol xaml (i cut the repeated SplineColorKeyFrame tags)
<UserControl
x:Class="Svdh.SmStation.AutoCash.Biz.LoadingPanelSopra_6_12"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ctrls="clr-namespace:Svdh.Controls.WPF;assembly=Svdh.Controls.WPF"
xmlns:local="clr-namespace:Svdh.SmStation.AutoCash.Biz;assembly="
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:svdhAuto="clr-namespace:Svdh.Automation.Config;assembly=Svdh.Automation.Config"
mc:Ignorable="d"
d:Height="16"
d:Width="16" >
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Svdh.SmStation.AutoCash.Biz;Component/Resources/StylesThemeFree.xaml"/>
<ResourceDictionary Source="/Svdh.SmStation.AutoCash.Biz;component/Resources/Skin_Classic_Blue.xaml" />
<ResourceDictionary Source="/Svdh.SmStation.AutoCash.Biz;component/Resources/Skin_HighContrast_Yellow.xaml" />
</ResourceDictionary.MergedDictionaries>
<!-- ottimizzazione $HELP: http://mrpfister.com/journal/improving-wpf-rendering-performance/ -->
<Storyboard x:Key="ProgressAnimation_6_12" Completed="onStoryBoardCompleted" Timeline.DesiredFrameRate="5" RenderOptions.BitmapScalingMode="LowQuality">
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block12" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
<SplineColorKeyFrame KeyTime="00:00:00" Value="#AA000000"/>
and so on....
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block11" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
and so on....
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="#AA000000"/>
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block10" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
and so on....
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="#9B000000"/>
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block9" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
and so on....
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="#91000000"/>
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block8" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="#7F000000"/>
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block7" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="#72000000"/>
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block6" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="#63000000"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</ResourceDictionary>
</UserControl.Resources>
<Canvas x:Name="LayoutRoot" Height="32" Width="88">
<Grid Width="10.734" Height="10.004" Canvas.Left="38.614" Canvas.Top="0.331">
<local:Block x:Name="block6" RenderTransformOrigin="0.5,4.3689" OpacityMask="#64000000" VerticalAlignment="Top" Height="10.004">
<local:Block.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="-59.999999999999993"/>
<TranslateTransform/>
</TransformGroup>
</local:Block.RenderTransform>
</local:Block>
<local:Block x:Name="block7" RenderTransformOrigin="0.5,4.3689" OpacityMask="#72000000" VerticalAlignment="Top" Height="10.004">
<local:Block.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="0.99999999999999989" ScaleY="0.99999999999999989"/>
<SkewTransform/>
<RotateTransform Angle="-40"/>
<TranslateTransform/>
</TransformGroup>
</local:Block.RenderTransform>
</local:Block>
<local:Block x:Name="block8" RenderTransformOrigin="0.5,4.3689" OpacityMask="#80000000" VerticalAlignment="Top" Height="10.004">
<local:Block.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="-19.999999999999996"/>
<TranslateTransform/>
</TransformGroup>
</local:Block.RenderTransform>
</local:Block>
<local:Block x:Name="block9" OpacityMask="#8E000000" RenderTransformOrigin="0.5,4.3689" VerticalAlignment="Top" Height="10.004"/>
<local:Block x:Name="block10" RenderTransformOrigin="0.5,4.3689" OpacityMask="#9C000000" VerticalAlignment="Top" Height="10.004">
<local:Block.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="19.999999999999996"/>
<TranslateTransform/>
</TransformGroup>
</local:Block.RenderTransform>
</local:Block>
<local:Block x:Name="block11" RenderTransformOrigin="0.5,4.3689" OpacityMask="#AA000000" VerticalAlignment="Top" Height="10.004">
<local:Block.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="0.99999999999999989" ScaleY="0.99999999999999989"/>
<SkewTransform/>
<RotateTransform Angle="40"/>
<TranslateTransform/>
</TransformGroup>
</local:Block.RenderTransform>
</local:Block>
<local:Block x:Name="block12" RenderTransformOrigin="0.5,4.3689" OpacityMask="#B8000000" VerticalAlignment="Top" Height="10.004">
<local:Block.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="59.999999999999993"/>
<TranslateTransform/>
</TransformGroup>
</local:Block.RenderTransform>
</local:Block>
</Grid>
</Canvas>
</UserControl>
To complete the scenario, here the code behind of the usercontrol in which I activate the storyboard animation via the AttachedProperty AnimationEnabled
Public Shared ReadOnly AnimationEnableProperty As DependencyProperty = DependencyProperty.Register("AnimationEnable",
GetType(Boolean),
GetType(LoadingPanelSopra_6_12),
New PropertyMetadata(False, AddressOf OnDependencyPropertyChanged))
Public Property AnimationEnable As Boolean
Get
Return CBool(Me.GetValue(AnimationEnableProperty))
End Get
Set(value As Boolean)
Const METHOD_NAME As String = "AnimationEnable.SET()"
Try
Me.SetValue(AnimationEnableProperty, value)
Catch ex As Exception
Svdh.Dbg.IgnoreFirstChance(ex, Me, "{0}.ERL_{1}: ingored", METHOD_NAME, Erl.ToString)
End Try
End Set
End Property
which call the
Private Shared Sub OnDependencyPropertyChanged(d As DependencyObject, e As DependencyPropertyChangedEventArgs)
Dim tbh As LoadingPanelSopra_6_12 = TryCast(d, LoadingPanelSopra_6_12)
Select Case e.Property.Name
Case "AnimationEnable"
tbh.AnimationEnable_Local = CBool(e.NewValue)
End Select
End Sub
who effectively triggers the interesting code
Private WriteOnly Property AnimationEnable_Local As Boolean
Set(value As Boolean)
If (value) Then
Me.Visibility = Windows.Visibility.Visible
Me.IsEnabled = True
Me.StartAnimation()
Else
Me.IsEnabled = True
Me.StopAnimation()
Me.Visibility = Windows.Visibility.Hidden
End If
End Set
End Property
The last step in the sequence is doing by the following
Private Sub StartAnimation()
Dim SB As Storyboard = DirectCast(FindResource("ProgressAnimation_6_12"), Storyboard)
SB.Stop()
Mouse.OverrideCursor = Nothing
SB.Begin()
Mouse.OverrideCursor = Cursors.Wait
End Sub
Private Sub StopAnimation()
Dim SB As Storyboard = DirectCast(FindResource("ProgressAnimation_6_12"), Storyboard)
SB.Stop()
Mouse.OverrideCursor = Nothing
End Sub
Private Sub onStoryBoardCompleted(sender As Object, e As EventArgs)
Dim SB As Storyboard = DirectCast(FindResource("ProgressAnimation_6_12"), Storyboard)
If Me.AnimationEnable <> True Then
SB.Stop()
Mouse.OverrideCursor = Nothing
Else
SB.Begin()
Mouse.OverrideCursor = Cursors.Wait
End If
End Sub
As I told in the preface, Mouse.OverrideCursor = Cursors.Wait
and relative Mouse.OverrideCursor = Nothing
have effect (the mouse is displayed correctly) but the corresponding SB.Begin()
and SB.Stop()
really operates only if a System.Windows.MessageBox is shown in the middle of the buttonClick event method.
Thank you.