I want to reuse a storyboad defined in a resourcedictionnary and referenced in App.xaml
<Storyboard x:Key="ShowWindowStoryboard">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)"
>
<EasingDoubleKeyFrame KeyTime="0:0:0.3"
Value="1" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)"
>
<EasingDoubleKeyFrame KeyTime="0:0:0.3"
Value="1" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)"
>
<EasingDoubleKeyFrame KeyTime="0:0:0.3"
Value="1" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
and here the code that gave an exception
Storyboard sb = (FindResource("ShowWindowStoryboard") as Storyboard).Clone();
DoubleAnimation da0 = sb.Children[0] as DoubleAnimation;
/* Exception here da0 is null*/
Storyboard.SetTarget(da0, uc);
DoubleAnimation da1 = sb.Children[1] as DoubleAnimation;
Storyboard.SetTarget(da1, uc);
DoubleAnimation da2 = sb.Children[2] as DoubleAnimation;
Storyboard.SetTarget(da2, uc);
sb.Begin();
i have also checked that sb.children.Count == 3 as expected.
You have to add a TransformGroup to the RenderTransform of your uc control. I will be adding a TransformGroup to an Image. The same will work for your control uc.
XAML
<Image Source="untitled.bmp" Name="ImgDemo">
<Image.RenderTransform>
<TransformGroup>
<ScaleTransform/>
</TransformGroup>
</Image.RenderTransform>
</Image>
If you have to add TransformGroup in code behind, you can use following before calling Story.Begin:
TransformGroup transformGroup = new TransformGroup();
transformGroup.Children.Add(new ScaleTransform(1,1));
uc.RenderTransform = transformGroup;
Your Storyboard.TargetProperty should reflect the signature of the object that you want the storyboard to be applied to. This is why you were facing the exception. Also, you might want to change your Storyboard a little to actually see the changes on the object. Like,
<Storyboard x:Key="ShowWindowStoryboard">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)"
>
<EasingDoubleKeyFrame KeyTime="0:0:0.3"
Value="0.5" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)"
>
<EasingDoubleKeyFrame KeyTime="0:0:0.3"
Value="0.5" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)"
>
<EasingDoubleKeyFrame KeyTime="0:0:0.3"
Value="0.5" />
</DoubleAnimationUsingKeyFrames>
Note that the values are changed so that the animations will be noticeable. Finally, I do see that your code behind on calling the storyboard does not use proper casting. So you might wanna consider using the following,
Storyboard sb = (FindResource("ShowWindowStoryboard") as Storyboard).Clone();
DoubleAnimationUsingKeyFrames da0 = sb.Children[0] as DoubleAnimationUsingKeyFrames;
Storyboard.SetTarget(da0, ImgDemo);
DoubleAnimationUsingKeyFrames da1 = sb.Children[1] as DoubleAnimationUsingKeyFrames;
Storyboard.SetTarget(da1, ImgDemo);
DoubleAnimationUsingKeyFrames da2 = sb.Children[2] as DoubleAnimationUsingKeyFrames;
Storyboard.SetTarget(da2, ImgDemo);
sb.Begin();
Good luck!
Related
I've made an opacity animation using Blend on one my two UserControls, deleted <UserControl.Resources>, <UserControl.Triggers> and Storyboard.TargetName from that, placed it in App.xaml and it looks like:
<Storyboard x:Key="Loaded">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" >
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:3" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
when I call it in code like this before setting the Content of my ContentControl:
Storyboard sb = FindResource("Loaded") as Storyboard;
sb.begin(uc1);
content.Content = uc1;
//and
Storyboard sb = FindResource("Loaded") as Storyboard;
sb.begin(uc2);
content.Content = uc2;
it works as expected. For the transform animation, I've deleted the TransformGroup as well in addition to those above and now it looks like:
<Storyboard x:Key="Unloaded">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:3" Value="-800"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
If I call it in the same way, I get this error:
System.InvalidOperationException: ''[Unknown]' property does not point to a DependencyObject in path '(0).(1)[3].(2)'.'
How to fix the problem?
You will need to add a RenderTransform to your UserControl which is similar to the Storyboard.TargetProperty which currently expects a TransformGroup with 4th child as TranslateTransform.
Add the below code to each of your two UserControls:
<UserControl x:Class="YourUserControl"
...>
<UserControl.RenderTransform>
<TransformGroup>
<RotateTransform/>
<ScaleTransform/>
<SkewTransform/>
<TranslateTransform/>
</TransformGroup>
</UserControl.RenderTransform>
I have a frame within my main page that I have set up to stretch/slide over on a button click. I do not want the frame to stretch/slide on the first button click but rather when the user clicks that same button a second time.
XAML:
<Storyboard x:Key="FrameSlide">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)" Storyboard.TargetName="currentPage">
<SplineDoubleKeyFrame KeyTime="0" Value="1"/>
<SplineDoubleKeyFrame KeyTime="0:0:0.7" Value="1.217"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)" Storyboard.TargetName="currentPage">
<SplineDoubleKeyFrame KeyTime="0" Value="0"/>
<SplineDoubleKeyFrame KeyTime="0:0:0.7" Value="-126"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="FrameSlideBack">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)" Storyboard.TargetName="currentPage">
<SplineDoubleKeyFrame KeyTime="0" Value="1.217"/>
<SplineDoubleKeyFrame KeyTime="0:0:0.7" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)" Storyboard.TargetName="currentPage">
<SplineDoubleKeyFrame KeyTime="0" Value="-126"/>
<SplineDoubleKeyFrame KeyTime="0:0:0.7" Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Window.Resources>
<Window.Triggers>
<EventTrigger RoutedEvent="UIElement.MouseLeftButtonDown" SourceName="TransmitBTN">
<BeginStoryboard x:Name="FrameSlide" Storyboard="{StaticResource FrameSlide}"/>
</EventTrigger>
<EventTrigger RoutedEvent="UIElement.MouseLeftButtonDown" SourceName="PatientBTN">
<BeginStoryboard x:Name="FrameSlideBack" Storyboard="{StaticResource FrameSlideBack}"/>
</EventTrigger>
</Window.Triggers>
I've tried using the storyboard.stop() / storyboard.being() in my VB.net code for the button, but it seems like the xaml is over ridding the vb code. I've tired doing if statements where my frame is a certain width then do nothing else trigger the animation.
Not sure where to go from here.
Thanks
I am answering this in C# as i dont know VB but from what I am told you can change it easily?
The answer I can come with us is make an event on the button, button_click, within the class create a public property. In the event increment the property and when it reaches two, trigger your story board.
XAML for button event:
<Button x:Name="button" Content="Button" Click="Button_OnClick"
C# code:
public partial class StackOverFlowExample
{
public StackOverFlowExample()
{
InitializaComponent();
buttonClickCounter = 0;
}
public int buttonClickCounter {get; set;}
private void Button_Click(object sender, RoutedEventArgs e)
{
buttonClickCounter++;
if (buttonClickCounter == 2)
{
buttonClickCounter = 0;
Storyboard sb = Application.Current.Resources["FrameSlide"] as
Storyboard;
if (sb.IsSealed)
sb = sb.Clone();
Storyboard.SetTarget(sb, this.NextButton);
sb.Completed += delegate { };
sb.Begin();
}
e.Handled = true;
}
}
I have a program where the user needs to navigate through back and forth. Basically there's {Dashboard, Settings ... }
I implemented them using a User Control, so I have my Window, and my User Controls that load in it.
The page switcher code I used to navigate between them I found there (azerdark.wordpress.com/2010/04/23/multi-page-application-in-wpf)
What I want is to animate the way the User Controls navigate when they are loaded in my window.
The simplest thing I found would be to create a Frame over my Window and animate it .. which I did, but I'm having trouble raising the event that fires the animation. I tried animating on window loaded just for testing and it works fine, but when the User Controls are loaded in my windows the animation is not working.
Here's my code
XAML: {PageSwitcher - My Window where the User Controls are loaded}
<Window.Resources>
<Storyboard x:Key="FadeLeft">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)" Storyboard.TargetName="myFrame">
<EasingDoubleKeyFrame KeyTime="0" Value="900">
<EasingDoubleKeyFrame.EasingFunction>
<ExponentialEase EasingMode="EaseOut" Exponent="5"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="0">
<EasingDoubleKeyFrame.EasingFunction>
<ExponentialEase EasingMode="EaseOut" Exponent="5"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="myFrame">
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
<DiscreteObjectKeyFrame KeyTime="0:0:0.5" Value="{x:Static Visibility.Visible}"/>
<DiscreteObjectKeyFrame KeyTime="0:0:0.6" Value="{x:Static Visibility.Hidden}"/>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="myFrame">
<EasingDoubleKeyFrame KeyTime="0" Value="0">
<EasingDoubleKeyFrame.EasingFunction>
<PowerEase EasingMode="EaseOut" Power="2"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="1">
<EasingDoubleKeyFrame.EasingFunction>
<PowerEase EasingMode="EaseOut" Power="2"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Window.Resources>
<Frame x:Name="myFrame" Content="" Background="#FF8F4646" Visibility="Hidden" ScrollViewer.VerticalScrollBarVisibility="Disabled" RenderTransformOrigin="0.5,0.5">
<i:Interaction.Triggers>
<i:EventTrigger EventName="x:Static local:PageSwitcher.ainmate">
<ei:ControlStoryboardAction Storyboard="{StaticResource FadeLeft}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<Frame.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</Frame.RenderTransform>
</Frame>
XAML.cs
public static readonly RoutedEvent animate = EventManager.RegisterRoutedEvent(
"Fade", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(PageSwitcher));
public event RoutedEventHandler Fade
{
add { AddHandler(animate, value); }
remove { RemoveHandler(animate, value); }
}
public void RaiseAnimateEvent()
{
RoutedEventArgs newEventArgs = new RoutedEventArgs(PageSwitcher.animate);
RaiseEvent(newEventArgs);
}
The event for the animation gets raised in my Switcher class just before Navigate is called to load the content of the User Control into my Window
XAML.cs {Switcher -- only sets the content of my window to the User Control passed when Navigate is called.}
public static void Switch(UserControl newPage)
{
pageSwitcher.Navigate(newPage);
pageSwitcher.RaiseAnimateEvent();
}
Is there anything wrong with my code? Why isn't the animation working?
The frame doesn't show when I navigate between the UserControls
Thanks for any help
Is this just me or what? RepeatBehavior doesn't seem work for animations in Expression Blend 4. I have the following animation:
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)"
Storyboard.TargetName="WaitDoc" RepeatBehavior="0:0:2">
<EasingDoubleKeyFrame KeyTime="0:0:1.0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.1" Value="180"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.2" Value="360"/>
</DoubleAnimationUsingKeyFrames>
I expect this animation to run for 2 seconds, but instead it runs only once when I click Play button in Objects and Timeline pane. I have tried values like 5x too, getting the same behavior.
I don't want to run the entire project to test every minute change. The Play button SHOULD play it as defined. Am I missing something here?
EDIT: In addition, I just discovered that Blend also doesn't show any respect for BeginTime attribute.
Try this :
<DoubleAnimationUsingKeyFrames
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children) [2].(RotateTransform.Angle)"
Storyboard.TargetName="WaitDoc" Duration="0:0:2" RepeatBehavior="Forever">
<EasingDoubleKeyFrame KeyTime="0:0:1.0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.1" Value="180"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.2" Value="360"/>
</DoubleAnimationUsingKeyFrames>
I Have Animation In My ResourceDictionary But I Want Call Animation In My C# Code.
This ResourceDictionary Add To My Resources App
Example:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<BeginStoryboard x:Key="PuzzleFall">
<Storyboard Storyboard.TargetName="RenderT" Storyboard.TargetProperty="X">
<DoubleAnimationUsingKeyFrames Duration="0:0:3" BeginTime="0:0:0">
<SplineDoubleKeyFrame Value="0" KeySpline="1 0,0.95 0" KeyTime="0:0:3"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="0:0:3.06" Duration="0:0:1.5">
<SplineDoubleKeyFrame Value="50" KeySpline="0 1,0 1" KeyTime="0:0:1.5"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="0:0:3.08" Duration="0:0:1">
<SplineDoubleKeyFrame Value="0" KeySpline="1 0,1 0" KeyTime="0:0:1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="0:0:4.1" Duration="0:0:1">
<SplineDoubleKeyFrame Value="15" KeySpline="0 1,0 1" KeyTime="0:0:1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="0:0:4.15" Duration="0:0:0.5">
<SplineDoubleKeyFrame Value="0" KeySpline="1 0,1 0" KeyTime="0:0:0.5"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</ResourceDictionary>
Then I Want Run This Animation In C# Code.
Thanks.
You probably should not put the Storyboard which is the main component inside a BeginStoryboard especially if you use code. EIther way. you can get the Storyboard using FindResource.
In your current setup something like this:
var beginsb = (BeginStoryboard)FindResource("PuzzleFall");
var sb = beginsb.Storyboard;
sb.Begin();