How to remove Storyboard after begin it in UWP? - c#

I'm working on the UI animations with my UWP project. When I combined the Storyboard with translate transform based on user's manipulation in a control, it's seem like the tranlastion didn't work anymore after the Storyboard had begun its animation.
After researching, I thought this is the reason -
that I can't change the value of a property after it has been animated, and I have to remove the Storyboard,... Unfortunately this article is support for WPF so I can't apply to my UWP project. So does anyone know any solutions for this situation ?
XAML:
<Frame x:Name="StoreFrame"
Grid.Row="1"
Grid.RowSpan="1"
MaxWidth="400"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
ManipulationDelta="StoreFrame_OnManipulationDelta"
ManipulationMode="TranslateY">
<Frame.RenderTransform>
<CompositeTransform x:Name="Transform" />
</Frame.RenderTransform>
</Frame>
Manipulation event handler:
private void StoreFrame_OnManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
Transform.TranslateY += e.Delta.Translation.Y;
}
My Storyboard animation:
private void ShowStoreFrameAnimation()
{
VerticalAnimatiton(StoreFrame, StoreFrame.ActualHeight, 0);
}
public void VerticalAnimatiton(DependencyObject controlObject,
double fromValue, double toValue, double durationTime = 1000)
{
//The animation things
var storyboard = new Storyboard();
var duration = new Duration(TimeSpan.FromMilliseconds(durationTime));
var ease = new CubicEase { EasingMode = EasingMode.EaseOut };
var animation = new DoubleAnimation
{
EasingFunction = ease,
Duration = duration
};
storyboard.Children.Add(animation);
animation.From = fromValue;
animation.To = toValue;
animation.EnableDependentAnimation = false;
Storyboard.SetTarget(animation, controlObject);
Storyboard.SetTargetProperty(animation, "(UIElement.RenderTransform).(CompositeTransform.TranslateY)");
storyboard.Begin();
}

How to remove Storyboard after begin it in UWP?
I can't change the value of a property after it has been animated, and I have to remove the Storyboard.
As you said that we can't change the value of a property after it has been animated. And there is no viable way to remove the storyboard. But you can add the new storyboard for same property that has been used. the following code is a workaround for your scenario.
Add the new storyboard to the StoreFrame_OnManipulationDelta event method.
private void StoreFrame_OnManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
Transform.TranslateY += e.Delta.Translation.Y;
var duration = new Duration(TimeSpan.FromMilliseconds(1000));
var ease = new CubicEase { EasingMode = EasingMode.EaseOut };
var animation = new DoubleAnimation
{
EasingFunction = ease,
Duration = duration
};
var conStoryboard = new Storyboard();
conStoryboard.Children.Add(animation);
animation.From = Transform.TranslateY;
animation.To = Transform.TranslateY += e.Delta.Translation.Y;
animation.EnableDependentAnimation = false;
Storyboard.SetTarget(animation, StoreFrame);
Storyboard.SetTargetProperty(animation, "(UIElement.RenderTransform).(CompositeTransform.TranslateY)");
conStoryboard.Begin();
}
Animation effect

Related

How to rotate animation my button when click in c# wpf

these are my declaration for my DoubleAnimation and storyboard
private Storyboard openmenurotateSB;
DoubleAnimation openMenuRotate = new DoubleAnimation();
openMenuRotate.From = 0;
openMenuRotate.To = 90;
openMenuRotate.Duration = new Duration(TimeSpan.FromMilliseconds(1000));
openMenuRotate.FillBehavior = FillBehavior.Stop;
openMenuRotate.AutoReverse = true;
openmenurotateSB = new Storyboard();
openmenurotateSB.Children.Add(openMenuRotate);
Storyboard.SetTargetName(openMenuRotate, OpenMenuButton.Name);
Storyboard.SetTargetProperty(openMenuRotate, new PropertyPath(RotateTransform.AngleProperty));
when click, begin rotate animation
private void OpenMenu_Click(object sender, RoutedEventArgs e)
{
openmenurotateSB.Begin(OpenMenuButton);
}
There is no any error or exception, it just does not work.
Thanks in advance.
Xing Yik
A RotateTransform should be assigned to either the RenderTransform or the LayoutTransform property of the Button.
<Button Content="Open Menu" Click="OpenMenu_Click"
RenderTransformOrigin="0.5,0.5">
<Button.RenderTransform>
<RotateTransform x:Name="rotateTransform"/>
</Button.RenderTransform>
</Button>
You do not need to use a Storyboard. Just directly animate the RotateTransform.
private void OpenMenu_Click(object sender, RoutedEventArgs e)
{
var animation = new DoubleAnimation
{
To = 90,
Duration = TimeSpan.FromSeconds(1),
FillBehavior = FillBehavior.Stop,
AutoReverse = true
};
rotateTransform.BeginAnimation(
RotateTransform.AngleProperty, animation);
}
or if you don't want to assign an x:Name to the RotateTransform or have assigned the RenderTransform property in code behind:
((UIElement)sender).RenderTransform.BeginAnimation(
RotateTransform.AngleProperty, animation);

WPF MediaElement Opacity is not set after executing Storyline

I'm using DoubleAnimation and Storyboard to control Opacity of MediaElement. The animation itself works fine, but if I call Disappear and playVid after several seconds, the Opacity of the player remains 0! What's the problem?
public void playVid(string source, bool isMainVid)
{
player.Opacity = 1;
player.Play(); //player.Opacity is 0 here!
}
public void Disappear()
{
DoubleAnimation fadeOut = new DoubleAnimation
{
To = 0,
Duration = new Duration(TimeSpan.FromMilliseconds(1000))
};
fadeOut.Completed += (s, e) =>
{
player.Stop();
};
var storyboard = new Storyboard();
storyboard.Children.Add(fadeOut);
Storyboard.SetTargetName(fadeOut, player.Name);
Storyboard.SetTargetProperty(fadeOut, new PropertyPath(OpacityProperty));
storyboard.Begin(mainGrid, HandoffBehavior.SnapshotAndReplace); //mainGrid is player's parent
}
Use FillBehavior equal to Stop, but also set the Opacity of your player to the final opacity value (in the Completed handler). Otherwise, it will be reset to its value before the animation.
var fadeOut = new DoubleAnimation
{
To = 0,
Duration = new Duration(TimeSpan.FromMilliseconds(1000)),
FillBehavior = FillBehavior.Stop
};
fadeOut.Completed += (s, e) =>
{
player.Stop();
player.Opacity = 0;
};
See this post for other approaches.

Shifting a Button Animation using System.Windows.Media.Animation

I have a Button in my Window, how do I use code behind in C# to go about animating it to shift to the left by lets say 100 pixels once I click on it.
private void myButton_Click(object sender, System.Windows.RoutedEventArgs e)
{
// TODO: Add event handler implementation here.
DoubleAnimation _DoubleAnimation = new DoubleAnimation();
_DoubleAnimation.From = 0;
_DoubleAnimation.To = 100;
_DoubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(1));
myButton.BeginAnimation(Button.RenderTransformOriginProperty, _DoubleAnimation);
}
If you want to change the size, in this case must be WidthProperty in Animation:
myButton.BeginAnimation(Button.WidthProperty, _DoubleAnimation);
To avoid sharp transition in the Animation, you must explicitly set the Width of the Button:
<Button Name="myButton"
Width="30"
Content="Test"
Click="myButton_Click" />
And in Animation specify only To value:
private void myButton_Click(object sender, System.Windows.RoutedEventArgs e)
{
DoubleAnimation _DoubleAnimation = new DoubleAnimation();
_DoubleAnimation.To = 100;
_DoubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(1));
myButton.BeginAnimation(Button.WidthProperty, _DoubleAnimation);
}
If you want to shift Button in Animation, you can use ThicknessAnimation:
Thanks for the remark to #Rohit Vats
private void myButton_Click(object sender, System.Windows.RoutedEventArgs e)
{
ThicknessAnimation animation = new ThicknessAnimation(new Thickness(0),
new Thickness(100, 0, 0, 0),
new Duration(new TimeSpan(0, 0, 1)),
FillBehavior.HoldEnd);
myButton.BeginAnimation(Button.MarginProperty, animation);
}
If you want to shift button to left by 100 pixels, you have to set margin to -100 of last value which obviously can't be achieved by DoubleAnimation since it can animate only double values whereas Margin is of type Thickness.
You can achieved that using Storyboard:
Storyboard myStoryboard = new Storyboard();
ObjectAnimationUsingKeyFrames animation = new ObjectAnimationUsingKeyFrames();
animation.BeginTime = TimeSpan.FromSeconds(0);
Storyboard.SetTarget(animation, myButton);
Storyboard.SetTargetProperty(animation, new PropertyPath("Margin"));
double left = myButton.Margin.Left - 100;
DiscreteObjectKeyFrame keyFrame = new DiscreteObjectKeyFrame(new Thickness(left,
0, 0, 0), TimeSpan.FromSeconds(1));
animation.KeyFrames.Add(keyFrame);
myStoryboard.Children.Add(animation);
myStoryboard.Begin();
For smooth transition what you can do is add multiple key frames and play them in interval of 0.1 secs. In case you need more smooth transition, break it down to further smaller intervals.
This is how you do it:
Storyboard myStoryboard = new Storyboard();
ObjectAnimationUsingKeyFrames animation = new ObjectAnimationUsingKeyFrames();
animation.BeginTime = TimeSpan.FromSeconds(0);
Storyboard.SetTarget(animation, myButton);
Storyboard.SetTargetProperty(animation, new PropertyPath("Margin"));
for (int count = 1; count < 21; count++)
{
double left = myButton.Margin.Left - (5 * count);
DiscreteObjectKeyFrame keyFrame = new DiscreteObjectKeyFrame(new
Thickness(left, 0, 0, 0), TimeSpan.FromSeconds(0.05 * count));
animation.KeyFrames.Add(keyFrame);
}
myStoryboard.Children.Add(animation);
myStoryboard.Begin();
It is depends how you have placed the Button on the page. If you want to layout elements by coordinates (not recommended) you can place the button on Canvas. Then you can use code like this:
<Canvas>
<Button Canvas.Left="100" Canvas.Top="100" Name="btnOk" HorizontalAlignment="Center" VerticalAlignment="Center" Width="50" Click="BtnOk_OnClick">Ok</Button>
</Canvas>
and code-behind:
var doubleAnimation = new DoubleAnimation();
double left = Canvas.GetLeft(btnOk);
doubleAnimation.From = left;
doubleAnimation.To = left - 100;
doubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(1));
btnOk.BeginAnimation(Canvas.LeftProperty, doubleAnimation);

Resizing animation on SizeChanged event doesn't work as it should

I want a resizing animation when stackpanel visibility is set to visible state, but instead of that, I'm getting neverending flickering of border containing stackpanel.I don't think I'm doing it wrong.
Stack panel contains an instance of TextBlock.
private void MyBorder_SizeChanged_1(object sender, SizeChangedEventArgs e)
{
if (!first)
{
DoubleAnimation anim = new DoubleAnimation();
anim.From = e.PreviousSize.Height;
anim.To = e.NewSize.Height;
anim.Duration = new Duration(TimeSpan.FromSeconds(1));
Storyboard.SetTarget(anim, MyBorder);
Storyboard.SetTargetProperty(anim, new PropertyPath(Border.HeightProperty));
Storyboard st = new Storyboard();
st.Children.Add(anim);
st.Begin();
}
first = false;
}
private void MyBorder_Tap_1(object sender, GestureEventArgs e)
{
if (MyPanel.Visibility == Visibility.Collapsed)
MyPanel.Visibility = Visibility.Visible;
else
MyPanel.Visibility = Visibility.Collapsed;
}
The problem is that when you animate the height of the border it will trigger the SizeChanged event so you have a loop: size changed event>animate height>size changed event> ..
Also when the sized changed event is fired, the size change has already taken placed so even if that was working you will get a little flicking when it go back to do the animation.
Finally using HEight in an animation force a rendering update so that is not hardware accelerated.
Probably the best would be to either do a Translate Transform or a Scale Transform.
For exemple you could do a scale transform between 0 and 1 directly on MyPanel in the tap event.
This might help you to. It is a work around
private void MyBorder_SizeChanged_1(object sender, SizeChangedEventArgs e)
{
if (!first)
{
DoubleAnimation anim = new DoubleAnimation();
anim.From = e.PreviousSize.Height;
anim.To = e.NewSize.Height;
anim.Duration = new Duration(TimeSpan.FromSeconds(1));
Storyboard.SetTarget(anim, MyBorder);
Storyboard.SetTargetProperty(anim, new PropertyPath(Border.HeightProperty));
Storyboard st = new Storyboard();
st.Children.Add(anim);
st.Completed += st_Completed;
MyBorder.SizeChanged -= MyBorder_SizeChanged_1;
st.Begin();
}
first = false;
}
void st_Completed(object sender, EventArgs e)
{
MyBorder.SizeChanged += MyBorder_SizeChanged_1;
}
private void MyBorder_Tap_1(object sender, GestureEventArgs e)
{
if (MyPanel.Visibility == Visibility.Collapsed)
MyPanel.Visibility = Visibility.Visible;
else
MyPanel.Visibility = Visibility.Collapsed;
}
With reference to the fact that border is getting resized even in the storyboard its better to remove the event of size changed. Try animating the parent container on chld size changed some thing kind of this
I've solved this problem. Silly my, I thought that Measure method of StackPanel is private, and didn't bother to make sure about it, here's solution code for expanding StackPanel on Click.
private void MyBorder_Tap_1(object sender, GestureEventArgs e)
{
if (MyPanel.Visibility == Visibility.Collapsed)
{
MyPanel.Visibility = Visibility.Visible;
MyPanel.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));
DoubleAnimation anim = new DoubleAnimation();
anim.From = MyBorder.ActualHeight;
anim.To = MyBorder.ActualHeight + MyPanel.DesiredSize.Height;
anim.Duration = new Duration(TimeSpan.FromSeconds(0.25));
Storyboard.SetTarget(anim, MyBorder);
Storyboard.SetTargetProperty(anim, new PropertyPath(Border.HeightProperty));
Storyboard st = new Storyboard();
st.Children.Add(anim);
st.Begin();
}
else
{
MyPanel.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));
DoubleAnimation anim = new DoubleAnimation();
anim.From = MyBorder.ActualHeight;
anim.To = MyBorder.ActualHeight - MyPanel.DesiredSize.Height;
anim.Duration = new Duration(TimeSpan.FromSeconds(0.25));
Storyboard.SetTarget(anim, MyBorder);
Storyboard.SetTargetProperty(anim, new PropertyPath(Border.HeightProperty));
Storyboard st = new Storyboard();
st.Children.Add(anim);
st.Completed += (a,b) => { MyPanel.Visibility = Visibility.Collapsed; };
st.Begin();
}
}

Cannot set Opacity property on ScatterViewItem after an animation has been performed

I am currently removing an element from the user interface by fading it out. This works as expected.
public void HideShape()
{
if (this.TangibleShape != null)
{
DoubleAnimation animation = new DoubleAnimation();
animation.From = 1.0;
animation.To = 0.0;
animation.AutoReverse = false;
animation.Duration = TimeSpan.FromSeconds(1.5);
Storyboard s = new Storyboard();
s.Children.Add(animation);
Storyboard.SetTarget(animation, this.TangibleShape.Shape);
Storyboard.SetTargetProperty(animation, new PropertyPath(ScatterViewItem.OpacityProperty));
s.Begin(this.TangibleShape.Shape);
s.Completed += delegate(object sender, EventArgs e)
{
// call UIElementManager to finally hide the element
UIElementManager.GetInstance().Hide(this.TangibleShape);
};
}
}
The problem is that I want to set the opacity to 1 again in some cases but the TangibleShape.Shape (it's a ScatterViewItem) ignores the command. If I fade out again, the element becomes visible and immediately starts fading out. I don't know how to fix this problem. Does anyone have a hint for me?
public void HideShape()
{
if (this.TangibleShape != null)
{
DoubleAnimation animation = new DoubleAnimation();
animation.From = 1.0;
animation.To = 0.0;
animation.AutoReverse = false;
animation.Duration = TimeSpan.FromSeconds(1.5);
animation.FillBehavior = FillBehavior.Stop; // needed
Storyboard s = new Storyboard();
s.Children.Add(animation);
Storyboard.SetTarget(animation, this.TangibleShape.Shape);
Storyboard.SetTargetProperty(animation, new PropertyPath(ScatterViewItem.OpacityProperty));
s.Completed += delegate(object sender, EventArgs e)
{
// call UIElementManager to finally hide the element
UIElementManager.GetInstance().Hide(this.TangibleShape);
this.TangibleShape.Shape.Opacity = 0.0; // otherwise Opacity will be reset to 1
};
s.Begin(this.TangibleShape.Shape); // moved to the end
}
}
Answer found here: http://social.msdn.microsoft.com/Forums/en-US/7d33ca82-2c02-4004-8b37-47edf4cca34e/scatterviewitem-and-

Categories