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();
}
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 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.
so I have a contentcontrol that has a routedevent:
public class TestBlind : ContentControl
{
public static readonly RoutedEvent VisibilityVisibleEvent =
EventManager.RegisterRoutedEvent("VisibilityVisible", RoutingStrategy.Tunnel, typeof(Visibility), typeof(TestBlind));
public event RoutedEventHandler VisibilityVisible
{
add { AddHandler(VisibilityVisibleEvent, value); }
remove { RemoveHandler(VisibilityVisibleEvent, value); }
}
[Category("TestBlind")]
public bool IsContentVisible
{
get { return (bool)GetValue(IsContentVisibleProperty); }
set { SetValue(IsContentVisibleProperty, value); }
}
public static readonly DependencyProperty IsContentVisibleProperty = DependencyProperty.Register("IsContentVisible", typeof(bool), typeof(TestBlind),
new FrameworkPropertyMetadata(new PropertyChangedCallback(OnIsOverlayContentVisibleChanged)));
private static void OnIsOverlayContentVisibleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
TestBlind blind = d as TestBlind;
if (blind != null)
SetVisibility(blind);
}
private static void SetVisibility(TestBlind blind)
{
blind.Visibility = blind.IsContentVisible ? Visibility.Visible : Visibility.Hidden;
blind.RaiseEvent(blind.Visibility == Visibility.Visible ? new RoutedEventArgs(VisibilityVisibleEvent) : new RoutedEventArgs(VisibilityHiddenEvent));
}
}
this event is fired when a dependency property is changed. What I want is to be able to fire an animation when the event fires.
In my resource file for the control I have the following exert that (I thought) would call see the event and start the animation:
<Grid.Triggers>
<EventTrigger RoutedEvent="control:TestBlind.VisibilityVisible">
<!-- <EventTrigger RoutedEvent="ContentControl.Loaded">-->
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimationUsingKeyFrames Duration="00:00:02.25" BeginTime="00:00:00" Storyboard.TargetName="backdDropGlow" Storyboard.TargetProperty="Opacity">
<SplineDoubleKeyFrame KeyTime="00:00:00.00" Value="0"/>
<SplineDoubleKeyFrame KeyTime="00:00:02.25" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
The animation will work if I use the ContentControl.Loaded (only the first time the control's property is changed though), but if I try and register it for my event nothing happens.
Is this possible, am I going about it completely wrong? I hope this made sense.
Thanks
Why not trigger your animation when the DependnecyProperty changes instead of using an Event?
I have done this in the past by attaching an event to the DependencyPropertyDescriptor in the Constructor
public TestBlind()
{
DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(TestBlind.VisibilityVisible, typeof(TestBlind));
if (dpd != null) dpd.AddValueChanged(this, delegate { IsVisibilityVisibleChanged(); });
}
private void IsVisibilityVisibleChanged()
{
bool isShown = GetVisibilityVisible(this);
if (isShown)
{
Storyboard animation = (Storyboard)this.FindResource("MyStoryboard");
animation.Begin();
}
}
I have a grid, a window root element. I want to apply an animation which would change it's background color from white to green in 5 seconds. Here's what I did:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
ColorAnimation animation;
animation = new ColorAnimation();
animation.From = Colors.White;
animation.To = Colors.Green;
animation.Duration = new Duration(TimeSpan.FromSeconds(5));
rootElement.BeginAnimation(Grid.BackgroundProperty, animation);
}
The code doesn't work. Nothing is changing. Where am I making a mistake? Thanks.
Solved!
private void Window_Loaded(object sender, RoutedEventArgs e)
{
SolidColorBrush rootElementBrush;
ColorAnimation animation;
rootElementBrush = this.FindResource("RootElementBrush") as SolidColorBrush;
// Animate the brush
animation = new ColorAnimation();
animation.To = Colors.Green;
animation.Duration = new Duration(TimeSpan.FromSeconds(5));
rootElementBrush.BeginAnimation(SolidColorBrush.ColorProperty, animation);
}
Here's an explanation:
My initial mistake was that I wanted to change the Grid.BackgroundProperty by assigning colors to it, but it accepts brushes instead... apples and oranges! So, I created a SolidColorBrush static resource and named it rootElementBrush. In XAML, I set Grid rootElement's background property to that static resource. And finally, I modified the animation, so now it changes the color for that SolidColorBrush. Easy!
Give this a try:
<ColorAnimation
Storyboard.TargetName="PlayButtonArrow"
Storyboard.TargetProperty="Fill.Color"
From="White"
To="Green"
Duration="0:0:5.0"
AutoReverse="False"/>
You do not need to set the StaticResource, just use the Storyboard.
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// Animate the brush
ColorAnimation animation = new ColorAnimation();
animation.To = Colors.Green;
animation.Duration = new Duration(TimeSpan.FromSeconds(5));
Storyboard.SetTargetProperty(animation, new PropertyPath("(Grid.Background).(SolidColorBrush.Color)", null));
Storyboard storyboard = new Storyboard();
storyboard.Children.Add(animation);
storyboard.Begin(rootElement);
}