Access a storyboard in window.resources from a template - c#

Given the following style, and a storyboard named animation that lives in <Window.Resources>, how can I pause (and resume) a storyboard triggered from code behind via ((Storyboard)FindResource("animate")).Begin(Tab1, true);
The following code errors saying the PauseStoryboard event can't find animate, which makes sense since it doesn't live in the template. The BeginStoryboard event allows you to bind to resources, but the pause and resume do not.
<Style x:Key="HiddenTabItem" TargetType="{x:Type TabItem}">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate DataType="{x:Type TabItem}">
<Border x:Name="grid">
<ContentPresenter>
<ContentPresenter.Content>
<TextBlock Text="{TemplateBinding Content}"/>
</ContentPresenter.Content>
</ContentPresenter>
</Border>
<DataTemplate.Triggers>
<EventTrigger RoutedEvent="MouseEnter">
<PauseStoryboard BeginStoryboardName="animate" />
</EventTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
The animate storyboard:
<Window.Resources>
<Storyboard x:Key="animate">
<ObjectAnimationUsingKeyFrames BeginTime="0:0:0" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimation BeginTime="0:0:0.0" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="0:0:0.2"/>
<DoubleAnimation BeginTime="0:0:2.5" Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="0:0:0.5"/>
<ObjectAnimationUsingKeyFrames BeginTime="0:0:5.5" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Hidden</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</Window.Resources>

how can I pause (and resume) a storyboard triggered from code behind
First off save the reference to the storyboard which was kicked off in codebehind in a convenient location. Since you now have that as a reference, subscribe to the mouse enter event from the control which you are targeting. Either in Xaml or most likely in codebehind use that reference to the storyboard to pause it.
Thus removing the need to use a style trigger.

Related

How do I start an animation by means of ButtonClick event?

I have some challenges with a code as follows.
I need to start this simpliest animation code by means of e.g. ButtonClick event or a method in Code Behind.
Could anyone shed the light on this matter?
Update: The code itself is working perfectly. I need just start it by a button. Not while window loading.
Thanks in advance!
<StackPanel>
<Button x:Name="Button" Content="Start" Click="Button_Click"/>
</StackPanel>
<Image
Name="img"
Width="128"
Height="128">
<Image.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard RepeatBehavior="Forever">
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Source" Duration="0:0:2.0">
<DiscreteObjectKeyFrame KeyTime="0:0:0">
<DiscreteObjectKeyFrame.Value>
<BitmapImage UriSource="D://Speakers//Wave_00.png" />
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
<DiscreteObjectKeyFrame KeyTime="0:0:.5">
<DiscreteObjectKeyFrame.Value>
<BitmapImage UriSource="D://Speakers//Wave_01.png" />
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
<DiscreteObjectKeyFrame KeyTime="0:0:1">
<DiscreteObjectKeyFrame.Value>
<BitmapImage UriSource="D://Speakers//Wave_02.png" />
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
<DiscreteObjectKeyFrame KeyTime="0:0:1.5">
<DiscreteObjectKeyFrame.Value>
<BitmapImage UriSource="D://Speakers//Wave_03.png" />
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Image.Triggers>
</Image>
</Grid>
try to change
eventtrigger routedevent="loaded"
in
EventTrigger RoutedEvent="Button_Click"
i hope it works

How to display a blinking overlay at runtime and turn it off again that is controlled by view model properties?

How to display a blinking notification message over parts of the main window of an application, while keeping the controls below of the overlay reachable (clickable) if the overlay is turned off?
The easy part is to create the overlay and build a storyboard for the animation:
<Window.Resources>
<Style x:Key="ds_NotificationStyle" TargetType="DockPanel">
<Setter Property="Opacity" Value="0" />
<Style.Triggers>
<DataTrigger Binding="{Binding EnableNotification}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Name="ds_BeginCallNotification">
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="0:0:0.2" />
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="1" To="0.4" Duration="0:0:0.4" AutoReverse="True" RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="ds_BeginCallNotification" />
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
Further below in the XAML, the overlay elements (there is a grid populated with other elements and the following DockPanel is placed above of them):
<DockPanel Grid.RowSpan="2" Name="ds_NotificationPanel" Style="{StaticResource ds_NotificationStyle}" Panel.ZIndex="200" Background="AntiqueWhite" Height="100" VerticalAlignment="top">
<Viewbox>
<TextBlock Text="{Binding IncomingCallNotification}" Margin="5" Foreground="Brown" FontWeight="Bold" />
</Viewbox>
</DockPanel>
But there is a problem now with the overlay, blocking all the controls underneath of it.
To solve this, the DockPanel's visibility has to be set to Collapsed. But how to adjust this visibility before and after the animation?
Toggle the visibility at the beginning, using an animation that targets runtime zero of the storyboard:
<ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
But at the same location, I had no idea how to reset the visibility back to Collapsed.
Using another Storyboard that is run at the ExitActions trigger solved this issue:
<ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="{x:Static Visibility.Collapsed}" />
</ObjectAnimationUsingKeyFrames>
Here is the complete solution (the DockPanel elements arent' changed):
<Window.Resources>
<Style x:Key="ds_NotificationStyle" TargetType="DockPanel">
<Setter Property="Opacity" Value="0" />
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding EnableNotification}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Name="ds_BeginCallNotification">
<Storyboard>
<ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="0:0:0.2" />
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="1" To="0.4" Duration="0:0:0.4" AutoReverse="True" RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="ds_BeginCallNotification" />
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="00:00:00.2" />
<ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="{x:Static Visibility.Collapsed}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
This may be easy and obvious for many of you, but it took me some times to figure it out. As I would have been grateful for such an answer, I have posted my solution here.

UserControl and Canvas - Vector Animation

I want to do a usercontrol, that show and hide (visible & collapsed) a vector object in my project. For that a got a canvas element in my grid.
And truing to make an animation of 2 object Layer1 and Layer2.
<UserControl.Resources>
<Storyboard x:Key="ProgressAnimation" RepeatBehavior="Forever">
<ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="Layer1" Storyboard.TargetProperty="Visibility">
<ObjectAnimationUsingKeyFrames.KeyFrames>
<DiscreteObjectKeyFrame KeyTime="00:00:01" Value="Visible"/>
</ObjectAnimationUsingKeyFrames.KeyFrames>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="Layer2" Storyboard.TargetProperty="Visibility">
<ObjectAnimationUsingKeyFrames.KeyFrames>
<DiscreteObjectKeyFrame KeyTime="00:00:02" Value="Visible"/>
</ObjectAnimationUsingKeyFrames.KeyFrames>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</UserControl.Resources>
Next I make a trigger :
<UserControl.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard x:Name="ProgressAnimationBeginStoryboard" Storyboard="{StaticResource ProgressAnimation}"/>
</EventTrigger>
</UserControl.Triggers>
And insert my element in to Grid :
<Grid>
<Canvas x:Name="Layer1" Margin="74,112,78,40" Visibility="Collapsed">
<Path Data="########" Fill="#FF00FF99" Height="148.219" Canvas.Left="0" Canvas.Top="0" Width="147.623"/>
</Canvas>
<Canvas x:Name="Layer2" Margin="74,113,79,40" Visibility="Collapsed">
<Path Data="########" Fill="#FF00FF99" Height="147.36" Canvas.Left="0" Canvas.Top="0" Width="147.243"/>
</Canvas>
</Grid>
In MainForm insert that code to XAML :
<Grid>
<control:LoadingForm HorizontalAlignment="Center" VerticalAlignment="Center" Height="298" Width="304"/>
</Grid>
And that not work properly - got that error :
Error 1 The animation(s) applied to the 'Visibility' property calculate a current value of 'Visible', which is not a valid value for the property. J:\Projects\LoadingPj\LoadingPj\MainWindow.xaml 1 2 LoadingPj
Who can help me to understand my problem?
Thx.
Try to specify Visibility.Visible value explicitly:
<DiscreteObjectKeyFrame KeyTime="00:00:01" Value="{x:Static Visibility.Visible}" />
Seems like it was treated as a string value.

How to bind a button's normal and pressed background image?

I've managed to save the button style into my AppSetting class based on this code here Cannot correctly populate ListPicker control with Image and Name
Then I want to bind the button's normal and pressed background images (I've several button styles which the user can select in the settings page).
<Style x:Key="ButtonStyle" TargetType="Button">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid Background="Transparent">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Disabled"/>
<VisualState x:Name="MouseOver"/>
<VisualState x:Name="Normal">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="NormalBackground">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="PressedBackground">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Collapsed</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="NormalBackground">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Collapsed</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="PressedBackground">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border x:Name="ButtonBackground" BorderBrush="{x:Null}">
<Grid>
<Image x:Name="NormalBackground" Source="{Binding ButtonUpSetting, Source={StaticResource AppSettings}}" Stretch="Uniform"/>
<Image x:Name="PressedBackground" Source="{Binding ButtonDownSetting, Source={StaticResource AppSettings}}" Stretch="Uniform"/>
<ContentControl x:Name="ContentContainer" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Foreground="{TemplateBinding Foreground}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" Padding="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Grid>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
In particular I would like to bind the following items to their respective uri sources but can't perform 'live' binding.
<Image x:Name="NormalBackground" Source="{Binding ButtonUpSetting, Source={StaticResource AppSettings}}" Stretch="Uniform"/>
<Image x:Name="PressedBackground" Source="{Binding ButtonDownSetting, Source={StaticResource AppSettings}}" Stretch="Uniform"/>
I've also implemented INotifyPropertyChangedin my AppSetting class but the button style is not updated when I returned to the button page.
Update:
The button is only updated when I close and reopen the app. So it can read the values from the settings. But it isn't updated right after I change the setting.
The structure of the pages is like the following:
ButtonPage <> SettingPage <> AppSetting Class
So how do I make sure the ButtonPage "re-read" the settings in AppSetting class after I change them in the SettingPage? I am not sure the INotifyPropertyChanged notifies the ButtonPage because it's in the backstack while I make the changes on the SettingPage.
Setting the DataContext = AppSetting inside ButtonPage OnNavigatedTo event does not make any different.
I've figured it out.
Only define the Datacontext in the code not in XAML so
<Image x:Name="NormalBackground" Source="{Binding ButtonUpSetting}" Stretch="Uniform"/>
<Image x:Name="PressedBackground" Source="{Binding ButtonDownSetting}" Stretch="Uniform"/>
Then
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
//Rebind all bindings to update button background images
if (e.NavigationMode == NavigationMode.Back)
{
this.DataContext = null;
this.DataContext = settings;
}
....

Toggling visibility using ObjectAnimationUsingKeyFrames

Im not sure why the following is not working. I am attempting hiding and showing a textbox every .2 seconds for 1.2 seconds when the bound model property changes. can anyone see an issue with this style or how i am attempting to do this?
<Style x:Key="FlashStyle" TargetType="TextBlock">
<Style.Triggers>
<EventTrigger RoutedEvent="Binding.TargetUpdated" >
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="00:00:00.2" Value="{x:Static Visibility.Visible}"/>
<DiscreteObjectKeyFrame KeyTime="00:00:00.4" Value="{x:Static Visibility.Collapsed}"/>
<DiscreteObjectKeyFrame KeyTime="00:00:00.6" Value="{x:Static Visibility.Visible}"/>
<DiscreteObjectKeyFrame KeyTime="00:00:00.8" Value="{x:Static Visibility.Collapsed}"/>
<DiscreteObjectKeyFrame KeyTime="00:00:01" Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
</Style>
<TextBlock Text="{Binding Data.QuotePrice, UpdateSourceTrigger=PropertyChanged}" Style="{StaticResource FlashStyle}" />
The Binding.TargetUpdated event does not occur:
Occurs when a value is transferred from the binding source to the binding target, but only for bindings with the NotifyOnTargetUpdated value set to true.
Only thing i can think of besides precedence (which should be fine if this is your actual code).

Categories