I have a storyboard defined:
<Grid.Resources>
<Storyboard x:Key="MasterAnim" x:Name="MasterAnim" Duration="0:0:10" >
<DoubleAnimation x:Name="ANIMATABLE_WidthExp"
Storyboard.TargetName="ANIMELEMENT_SboardRect1"
Storyboard.TargetProperty="Width"
From="100"
To="800"
Duration="0:0:5" />
<DoubleAnimation x:Name="ANIMATABLE_HeightExp"
Storyboard.TargetName="ANIMELEMENT_SboardRect1"
Storyboard.TargetProperty="Height"
From="100"
To="800"
BeginTime="0:0:5"
Duration="0:0:5" />
</Storyboard>
</Grid.Resources>
Is there any way of capturing when each of the double animations are about to start? I need to call a method on the element that it's targeting before the animation starts but im not sure what the best way to go about it is.
There's no Started event, but you can handle the CurrentTimeInvalidated, CurrentStateInvalidated and Completed events on the DoubleAnimation. CurrentStateInvalidated is probably all you need.
private void DoubleAnimationCurrentTimeInvalidated(object sender, EventArgs e)
{
var clock = (AnimationClock) sender;
Debug.WriteLine(string.Format("CurrentTime: state={0}, progress={1}, time={2}", clock.CurrentState, clock.CurrentProgress, clock.CurrentTime));
}
private void DoubleAnimationCurrentStateInvalidated(object sender, EventArgs e)
{
var clock = (AnimationClock)sender;
Debug.WriteLine(string.Format("CurrentState: state={0}", clock.CurrentState));
}
private void DoubleAnimationCompleted(object sender, EventArgs e)
{
var clock = (AnimationClock) sender;
Debug.WriteLine(string.Format("Completed: state={0}", clock.CurrentState));
}
Ignoring the current time we get
CurrentState: state=Active
CurrentState: state=Filling
Completed: state=Filling
when the animation runs.
Related
I've these Load and Unload animations in App.xaml:
<Storyboard x:Key="Unload">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:3" Value="-800"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="Load">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)">
<EasingDoubleKeyFrame KeyTime="0" Value="800"/>
<EasingDoubleKeyFrame KeyTime="0:0:3" Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
In my code I'm calling those on Button Clicks like these:
sb1 = FindResource("Unload") as Storyboard;
sb2 = FindResource("Load") as Storyboard;
void Button_Click(object sender, RoutedEventArgs e)
{
uc1.RenderTransform = GetTG();
uc2.RenderTransform = GetTG();
sb1.Begin(uc2);
sb2.Begin(uc1);
content.Content = uc1;
}
//and
void Button_Click_1(object sender, RoutedEventArgs e)
{
uc2.RenderTransform = GetTG();
uc1.RenderTransform = GetTG();
sb2.Begin(uc2);
sb1.Begin(uc1);
content.Content = uc2;
}
GetTG returns a TransformGroup
TransformGroup GetTG()
{
var tg = new TransformGroup();
tg.Children.Add(new ScaleTransform());
tg.Children.Add(new SkewTransform());
tg.Children.Add(new RotateTransform());
tg.Children.Add(new TranslateTransform());
return tg;
}
with these only the Load animation works. How to make both work at the same time?
Apply the animation to the ContentControl. This should slide out the current Content/UserControl to the left and slide in the new Content/UserControl from the right:
void Button_Click(object sender, RoutedEventArgs e)
{
UnLoadAndLoad(uc1);
}
void Button_Click_1(object sender, RoutedEventArgs e)
{
UnLoadAndLoad(uc2);
}
void UnLoadAndLoad(object ucToBeLoaded)
{
if (content.Content != ucToBeLoaded)
{
content.RenderTransform = GetTG();
EventHandler completed = null;
completed = (ss, ee) =>
{
sb1.Completed -= completed;
content.Content = ucToBeLoaded;
//load
sb2.Begin(content);
};
sb1.Completed += completed;
//unload
if (content.Content != null)
sb1.Begin(content);
else
completed(this, EventArgs.Empty);
}
}
I have an Image and I'm trying to give the user the ability to change the animation of the image from several options. The user can select a new animation but sometimes the previous selected animation won't stop and I have 2 or more storyboards running at the same time on the Image.
I have this code:
private void animateZoom1(object sender, EventArgs e)
{
effectSample.RenderTransform.BeginAnimation(ScaleTransform.ScaleYProperty, (FindResource("LogoStoryboard_Zoom") as Storyboard).Children[0] as DoubleAnimation);
}
private void animateZoom(Boolean mode)
{
if (mode)
{
effectSample.RenderTransform = new ScaleTransform();
effectSample.RenderTransform.BeginAnimation(ScaleTransform.ScaleYProperty, (FindResource("LogoStoryboard_Zoom") as Storyboard).Children[0] as DoubleAnimation);
}
else
{
effectSample.RenderTransform.BeginAnimation(ScaleTransform.ScaleYProperty, null);
cancelAnimation("LogoStoryboard_Zoom");
}
}
private void animateZoom2(object sender, EventArgs e)
{
effectSample.RenderTransform.BeginAnimation(ScaleTransform.ScaleYProperty, (FindResource("LogoStoryboard_Zoom") as Storyboard).Children[1] as DoubleAnimation);
}
private void animateOpacity(Boolean mode)
{
if (mode)
{
(FindResource("LogoStoryboard_Opacity") as Storyboard).Begin(this, true);
}
else
{
cancelAnimation("LogoStoryboard_Opacity");
}
}
private void animateScaleX2(object sender, EventArgs e)
{
effectSample.RenderTransform.BeginAnimation(ScaleTransform.ScaleXProperty, (FindResource("LogoStoryboard_ScaleX") as Storyboard).Children[1] as DoubleAnimation);
}
private void animateScaleX(object sender, EventArgs e)
{
effectSample.RenderTransform.BeginAnimation(ScaleTransform.ScaleXProperty, (FindResource("LogoStoryboard_ScaleX") as Storyboard).Children[0] as DoubleAnimation);
}
private void animateScaleX(Boolean mode)
{
if (mode)
{
effectSample.RenderTransform = new ScaleTransform();
effectSample.RenderTransform.BeginAnimation(ScaleTransform.ScaleXProperty, (FindResource("LogoStoryboard_ScaleX") as Storyboard).Children[0] as DoubleAnimation);
}
else
{
effectSample.RenderTransform.BeginAnimation(ScaleTransform.ScaleXProperty, null);
cancelAnimation("LogoStoryboard_ScaleX");
}
}
private void cancelAnimation(String storyBoardName)
{
(FindResource(storyBoardName) as Storyboard).Stop(this);
(FindResource(storyBoardName) as Storyboard).Remove(this);
}
and this
<Storyboard x:Key="LogoStoryboard_Zoom" RepeatBehavior="Forever">
<DoubleAnimation
Storyboard.TargetName="effectSample"
Storyboard.TargetProperty="(Image.RenderTransform).(ScaleTransform.ScaleY)"
By="0.5"
Duration="0:0:0.5"
BeginTime="0:0:0"
Completed="animateZoom2" />
<DoubleAnimation
Storyboard.TargetName="effectSample"
Storyboard.TargetProperty="(Image.RenderTransform).(ScaleTransform.ScaleY)"
By="-0.5"
Duration="0:0:0.5"
BeginTime="0:0:0"
Completed="animateZoom1" />
</Storyboard>
<Storyboard x:Key="LogoStoryboard_Opacity" RepeatBehavior="Forever">
<DoubleAnimation
Storyboard.TargetName="effectSample"
Storyboard.TargetProperty="Opacity"
From="1"
To="0"
Duration="0:0:8"
BeginTime="0:0:1"/>
<DoubleAnimation
Storyboard.TargetName="effectSample"
Storyboard.TargetProperty="Opacity"
From="0"
To="1"
Duration="0:0:8"
BeginTime="0:0:10"/>
</Storyboard>
<Storyboard x:Key="LogoStoryboard_ScaleX" RepeatBehavior="Forever">
<DoubleAnimation
Storyboard.TargetName="effectSample"
Storyboard.TargetProperty="(Image.RenderTransform).(ScaleTransform.ScaleX)"
To="0.5"
Duration="0:0:3"
BeginTime="0:0:0"
Completed="animateScaleX2"/>
<DoubleAnimation
Storyboard.TargetName="effectSample"
Storyboard.TargetProperty="(Image.RenderTransform).(ScaleTransform.ScaleX)"
To="1.5"
Duration="0:0:3"
BeginTime="0:0:0"
Completed="animateScaleX"/>
</Storyboard>
Please help me stop the old storyboard :)
I have this storyboard that starts when you hover over a grid:
<Storyboard x:Key="SB_MouseEnter">
<DoubleAnimation To="0" Storyboard.TargetName="gridNav"
Storyboard.TargetProperty="(UIElement.RenderTransform).
(TranslateTransform.Y)"
Duration="0:0:0.2"/>
</Storyboard>
I would like to hover over it for 500ms before it does its animation. How to accomplish this?
Specify BeginTime on your storyboard at which you want timeline to begin (0.5 secs in your case):
<DoubleAnimation To="0" Storyboard.TargetName="gridNav"
Storyboard.TargetProperty="(UIElement.RenderTransform).
(TranslateTransform.Y)"
Duration="0:0:0.2"
BeginTime="0:0:0.5"/>
You could use the DispatcherTimer class to wait for 500ms in combination with the UIElement.MouseEnter and UIElement.MouseLeave events, before manually starting the Storyboard with the Begin method. Try something like this:
private DispatcherTimer timer;
private void OnMouseEnterHandler(object sender, MouseEventArgs e)
{
timer = new DispatcherTimer();
timer.Interval = new TimeSpan(0, 0, 0, 0, 500);
timer.Tick += Timer_Tick;
timer.Start();
}
private void OnMouseLeaveHandler(object sender, MouseEventArgs e)
{
timer.Stop();
}
private void Timer_Tick(object sender, EventArgs e)
{
SB_MouseEnter.Begin();
timer.Stop();
}
I have an application where there is a MainWindow at the top level with multiple UserControls housed inside it. I have a Button on one UserControls and want to trigger an animation in another UserControls. How to go about it? I have tried with Blend but the timeline does not allow me to access the other UserControls.
In short, I want to display a UserControl (say X) beside my existing application that will fade in on a button click. The button click is in another user control say Y, and both the UserControl X and the UserControl Y are inside MainWindow. I hope I have made myself clear.
An example:
<local:TimeBox x:Name="timeBox">
<local:TimeBox.RenderTransform>
<TranslateTransform />
</local:TimeBox.RenderTransform>
</local:TimeBox>
<local:CustomComboBox>
<local:CustomComboBox.Triggers>
<EventTrigger RoutedEvent="local:CustomComboBox.ApplyClick">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.Target="{x:Reference timeBox}"
Storyboard.TargetProperty="RenderTransform.X"
From="-500" To="0" Duration="0:0:1">
<DoubleAnimation.EasingFunction>
<ExponentialEase Exponent="5" EasingMode="EaseOut"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</local:CustomComboBox.Triggers>
</local:CustomComboBox>
Notes:
1 - The TranslateTransform cannot have a name so you need to navigate to it starting from the UserControl using RenderTransform.X
2 - The event that should trigger the animation needs to be a RoutedEvent, here is the code for the one i have:
public static RoutedEvent ApplyClickEvent = EventManager.RegisterRoutedEvent("ApplyClick",
RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(CustomComboBox));
public event RoutedEventHandler ApplyClick
{
add { AddHandler(ApplyClickEvent, value); }
remove { RemoveHandler(ApplyClickEvent, value); }
}
//Pipes the event from an internal button.
private void Button_Apply_Click(object sender, RoutedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(ApplyClickEvent, this));
}
I've been struggling with this for hours and I can't find out what I'm doing wrong. Please help me find my mistake.
I created a user control with one custom dependency property and I want to animate this property.
Here is my class:
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
public long Val
{
get { return (long)GetValue(ValProperty); }
set {
SetValue(ValProperty, value);
// Update a text block for debug
((Class1)this.Resources["class1"]).Val = value;
}
}
public static readonly DependencyProperty ValProperty =
DependencyProperty.Register("Val", typeof(long), typeof(UserControl1), new UIPropertyMetadata(0L));
}
Here is the code that is supposed to animate it (there's an instance of UserControl1 called usercontrol11):
Int64Animation myAnimation = new Int64Animation();
myAnimation.From = 100;
myAnimation.To = 200;
myAnimation.Duration = new Duration(TimeSpan.FromSeconds(1));
Storyboard.SetTargetName(myAnimation, userControl11.Name);
Storyboard.SetTargetProperty(myAnimation, new PropertyPath(UserControl1.ValProperty));
Storyboard myStoryboard = new Storyboard();
myStoryboard.Children.Add(myAnimation);
myStoryboard.Begin(this);
I also tried the XAML approach, but it didn't work either (in the following XAML, the Width animation works fine, but the Val doesn't):
<my:UserControl1 HorizontalAlignment="Left" Width="150" Margin="72,45,0,0" x:Name="userControl11" VerticalAlignment="Top" Background="#FFFFD100">
<my:UserControl1.Triggers>
<EventTrigger RoutedEvent="MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<Int64Animation To="300" Duration="0:0:1"
Storyboard.TargetProperty="Val" />
<DoubleAnimation To="300" Duration="0:0:1"
Storyboard.TargetProperty="Width" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</my:UserControl1.Triggers>
</my:UserControl1>
Any help will be much appreciated!
Well, it's actually animated. You're just checking in the wrong place, animation won't call Val property set accessor. You can, for example, override OnPropertyChanged method to see changes:
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
base.OnPropertyChanged(e);
if(e.Property == ValProperty)
{
MessageBox.Show(e.NewValue.ToString());
}
}