I have a complicated animation, which does some heavy changes to a view (changes visibility, opacity, background brushes, etc. of some controls) and I'd like to revert what this animation did. Stop/Remove storyboard "should" do that.
However, there is a problem:
The animation runs when one button is clicked, but stopped when another is clicked. And with this approach I am getting the following error.
System.Windows.Media.Animation Warning: 6 : Unable to perform action because the specified Storyboard was never applied to this object for interactive control.; Action='Remove' ......
Here is how I am doing it:
<!-- button which start animation -->
<Button ...>
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<EventTrigger.Actions>
<BeginStoryboard x:Name="storyboardUserClick">
<Storyboard>
<ObjectAnimationUsingKeyFrames ...
<!-- button which should revert what animation did --->
<Button ...>
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<EventTrigger.Actions>
<RemoveStoryboard BeginStoryboardName="storyboardUserClick" ...
Is there a simple way, preferably without code behind (well, attached property may be an option in worst case) to achieve that? I have feeling it is something very simple...
I found the answer here.
The idea is to move animation (I say animation, but I mean Storyboard and even more specifically BeginStoryboard) into a scope accessible by RemoveStoryboard. Something like
<Grid>
<Button x:Name="buttonStart" ...>
<Button x:Name="buttonStop" ...>
<Grid.Triggers>
<EventTrigger SourceName="buttonStart" RoutedEvent="Button.Click">
<BeginStoryboard x:Name="storyboardUserClick">
<Storyboard>
<ObjectAnimationUsingKeyFrames ...
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger SourceName="buttonStop" RoutedEvent="Button.Click">
<RemoveStoryboard BeginStoryboardName="storyboardUserClick" />
</EventTrigger>
</Grid.Triggers>
</Grid>
Related
We have a UserControl that mainly includes a XamTileManager (the actual control shouldn't matter) which is bound to a list of items. When the binding changes, we want to animate the transition between the old and new data with an arbitrary animation. Is that generally possible in WPF?
The alternative would of course be to have two UserControls and animate the change between them, but we want to avoid that if possible.
You can put a trigger inside the item with a storyboard. When the data changes the trigger will fire and launch the storyboard animation. I found this example which does it for a data binded textblock:
<TextBlock x:Name="tbMessage" Text="{Binding Path=StatusBarText, NotifyOnTargetUpdated=True}">
<TextBlock.Triggers>
<EventTrigger RoutedEvent="Binding.TargetUpdated">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity" Duration="0:0:0" To="1.0" />
<DoubleAnimation Storyboard.TargetProperty="Opacity" Duration="0:0:2" From="1.0" To="0.0" BeginTime="0:0:5" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</TextBlock.Triggers>
</TextBlock>
(source)
If that isnt quite what you want you can write your own animation by using the Binding.TargetUpdated event.
In my UserControl.Resources i have defined a Storyboard which triggers a DoubleAnimation to set the Opactiy.
<Storyboard AutoReverse="True" x:Key="BlinkingStoryBoard">
<DoubleAnimation Storyboard.TargetProperty="Opacity" To="0.1" Duration="0:0:2" RepeatBehavior="Forever"/>
</Storyboard>
This Storyboard is applied to a grid when the UserControl is loaded:
<Grid Name="ImagePlaceHolder">
<Rectangle Fill="#D52B1E" Width="75" Height="75"/>
<Image Source="pack://siteoforigin:,,,/Resources/Images/cross.png" Width="75" Height="75" RenderTransformOrigin="0.5, 0.5" x:Name="Cross"/>
<Grid.Triggers>
<EventTrigger RoutedEvent="UserControl.Loaded">
<BeginStoryboard Storyboard="{StaticResource BlinkingStoryBoard}"/>
</EventTrigger>
</Grid.Triggers>
</Grid>
From my code-behind I want to stop this animation, but I cant stop it!
((Storyboard)uc.FindResource("BlinkingStoryBoard")).Stop();
Any ideas?
Have a look at this reference.
The main idea is that you need to call the storyboard Stop method passing the container of the storyboard.
You should try replacing the stop call with this:
((Storyboard)uc.FindResource("BlinkingStoryBoard")).Stop(ImagePlaceHolder);
Also from the reference, it shows that you can name your BeginStoryboard, for example:
<BeginStoryboard Name="MyStoryboardStarter" Storyboard="{StaticResource BlinkingStoryBoard}"/>
Now in the code behind you can find your storyboard more easily and stop it like this:
MyStoryboardStarter.Storyboard.Stop(ImagePlaceHolder);
Hope this helps.
I am working on a c# wpf project and I have run in to a problem relating to firing an trigger within the XAML.
What I am trying to achieve is when the drags a file into the grid, it should animate the background colour change but for some reason it keeps on throwing an exception as soon as I run the program. I am getting the following error:
'Provide value on
'System.Windows.Baml2006.TypeConverterMarkupExtension' threw an
exception.' Line number '9' and line position '14'.
Below is the XAML code
<UserControl x:Class="ReportReader.UserControls.ReportDragDropControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008">
<Grid AllowDrop="True" DragDrop.DragOver="Grid_DragOver"
DragDrop.DragEnter="Grid_DragEnter" DragDrop.Drop="Grid_Drop" DragDrop.DragLeave="Grid_DragLeave">
<Grid.Triggers>
<EventTrigger RoutedEvent="Grid.DragEnter">
<BeginStoryboard>
<Storyboard>
<ColorAnimation To="#cecece" Storyboard.TargetProperty="(Grid.BackgroundColor).(SolidColorBrush.Color)" FillBehavior="Stop" Duration="0.0.1" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Grid.Triggers>
<TextBlock Margin="12,12,20,12" Name="txtDragDropStatus" Text="Drag file here or use file menu to load your report" TextAlignment="Center" FontSize="30" FontWeight="Bold" TextWrapping="WrapWithOverflow" Width="835" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</UserControl>
Thanks for any help you can provide.
There are two errors in your XAML file -
BackgroundColor is not a Dependency Property, instead use Background.
0.0.1 is not a valid value for TimeSpan. It should be 0:0:1.
This will work fine -
<ColorAnimation To="#cecece"
Storyboard.TargetProperty="(Grid.Background)
.(SolidColorBrush.Color)"
FillBehavior="Stop" Duration="0:0:1" />
Also, to allow animation on background property, you should set it to some default value.
<Grid Background="White"/>
I tried with this sample and its working fine on drag enter -
<Grid AllowDrop="True" Background="White" DragDrop.DragEnter="Grid_DragEnter">
<Grid.Triggers>
<EventTrigger RoutedEvent="Grid.DragEnter">
<BeginStoryboard>
<Storyboard>
<ColorAnimation To="#cecece"
Storyboard.TargetProperty="(Grid.Background).
(SolidColorBrush.Color)"
FillBehavior="Stop" Duration="0:0:1" />
</Storyboard>
</BeginStoryboard>
/EventTrigger>
</Grid.Triggers>
<TextBlock Margin="12,12,20,12" Name="txtDragDropStatus"
Text="Drag file here or use file menu to load your report"/>
</Grid>
I am doing a startup button which prompts the user to click it at the start.
I would like to animate my button at startup, with the animation of the button mouseover and mouseout continuously so that it looks like its blinking. And then stop animating it when it is clicked.
Any idea how to do so?
Your main storyboard would be instigated by the Loaded event of the button. Then you would have another event trigger on the Click event which removes the storyboard created in the Loaded event.
For example:
<Button>
<Button.Background>
<SolidColorBrush Color="White"/>
</Button.Background>
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Loaded">
<BeginStoryboard Name="MainStoryboard">
<Storyboard Storyboard.TargetProperty="Background.Color" Duration="00:00:02" RepeatBehavior="Forever">
<ColorAnimation To="Black" AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="Button.Click">
<RemoveStoryboard BeginStoryboardName="MainStoryboard"/>
</EventTrigger>
</Button.Triggers>
Test
</Button>
I'm creating a drag and drop behavior, and the goal is to drag an item onto my grid, where a set of adorned elements representing the available actions will be available for the user to drop the element on. My problem is once I add the adorned element(s) to the AdornerLayer, I don't receive any Drag events. I need to get those events to both change UI and set some underlying properties. I've set AllowDrop=true on the AdornerLayer, the adorned element, my button inside the DataTemplate inside the ContentPresenter, and on the ContentPresenter itself, but still don't get any events.
<DataTemplate x:Key="promoMediaTemplate" DataType="{x:Type media:PromoMediaSearchResult}">
<Button Content="{Binding Path=Description}" Name="item" AllowDrop="True" Background="Red" /
<DataTemplate.Triggers>
<EventTrigger RoutedEvent="Button.PreviewDragEnter">
<BeginStoryboard x:Name="TextBeginStoryBoard">
<Storyboard>
<ColorAnimation
Storyboard.TargetName="item"
Storyboard.TargetProperty="Background"
Duration="0:0:1.0"
From="Red" To="Green" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="Button.PreviewDragLeave">
<StopStoryboard BeginStoryboardName="TextBeginStoryBoard" />
</EventTrigger>
<EventTrigger RoutedEvent="Button.PreviewDrop">
<StopStoryboard BeginStoryboardName="TextBeginStoryBoard" />
</EventTrigger>
</DataTemplate.Triggers>
See this post: http://blogs.telerik.com/StefanDobrev/Posts/08-04-16/WPF_Series_Adorners_Commands_and_Logical_Tree.aspx