I am trying to create Sticky WPF window.
If window nearer left stick to left or stick right if nearer to right else stick to top
Below the code I am using,
private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
this.DragMove();
}
private void Window_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
Point currentPoints = PointToScreen(Mouse.GetPosition(this));
//Place left
if (currentPoints.X < (300))
{
DoubleAnimation moveAnimation = new DoubleAnimation(-190, TimeSpan.FromSeconds(1));
_MyWindow.BeginAnimation(Window.LeftProperty, moveAnimation);
}
//Place Right
else if (currentPoints.X > (Screen.PrimaryScreen.WorkingArea.Width - 300))
{
DoubleAnimation moveAnimation = new DoubleAnimation(Screen.PrimaryScreen.WorkingArea.Width + 190, TimeSpan.FromSeconds(1));
_MyWindow.BeginAnimation(Window.LeftProperty, moveAnimation);
}
//Place top
else
{
DoubleAnimation TopAnimation = new DoubleAnimation(-190, TimeSpan.FromSeconds(1));
_MyWindow.BeginAnimation(Window.TopProperty, TopAnimation, HandoffBehavior.Compose);
}
}
The above code moves window only once.
on MSDN, How to: Set a Property After Animating It with a Storyboard
To run animation again, set BeginAnimation Property to NULL,
I tried setting the property to NULL before animation.
And the code now works fine.
Now the code looks like
private void Window_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
Point currentPoints = PointToScreen(Mouse.GetPosition(this));
if (currentPoints.X < (300))
{
if (_MyWindow.HasAnimatedProperties)
_MyWindow.BeginAnimation(Window.LeftProperty, null);
DoubleAnimation moveAnimation = new DoubleAnimation(-190, TimeSpan.FromSeconds(1));
_MyWindow.BeginAnimation(Window.LeftProperty, moveAnimation);
}
else if (currentPoints.X > (Screen.PrimaryScreen.WorkingArea.Width - 300))
{
if (_MyWindow.HasAnimatedProperties)
_MyWindow.BeginAnimation(Window.LeftProperty, null);
DoubleAnimation moveAnimation = new DoubleAnimation(Screen.PrimaryScreen.WorkingArea.Width + 190, TimeSpan.FromSeconds(1));
_MyWindow.BeginAnimation(Window.LeftProperty, moveAnimation);
}
else
{
if (_MyWindow.HasAnimatedProperties)
_MyWindow.BeginAnimation(Window.TopProperty, null);
DoubleAnimation TopAnimation = new DoubleAnimation(-190, TimeSpan.FromSeconds(1));
_MyWindow.BeginAnimation(Window.TopProperty, TopAnimation, HandoffBehavior.Compose);
}
}
If Noticed, I am placing window at -190 position at left and top to hide some of its part.
But using
Below property, Its resetting the window position to 0.
I dont want it to reset the position
_MyWindow.BeginAnimation(Window.LeftProperty, null);
Can anybody suggest how to do multiple animation without resetting existing position?
Ashish Sapkale
I think your idea of setting LeftProperty to null is right but you should be doing that after the animation is finished.
So add a delegate to your animation and set the property to null in that and see if it works.
example
TopAnimation.Completed += (s,e) =>
{
_MyWindow.BeginAnimation(Window.TopProperty, null);
};
Your other options are to use ThicknessAnimation or TranslateTransform to move your window. Let me know if you are still having problems
Related
I want to animate my WPF window. It's set to size to content, so when the content changes, the window changes size. I don't want it to snap to a new size though, when it determines it needs a new size I want it to lerp between the old and new value with an animation.
How do I set this up?
EDIT:
I am using SizeToContent=WidthAndHeight" as a parameter for my window, and want to animate when it automatically sizes to different content being shown.
You may override the OnPropertyChanged method and start an animation of any property you like.
For example, the Width property:
private DoubleAnimation widthAnimation;
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
if (e.Property == WidthProperty &&
!double.IsNaN((double)e.OldValue) &&
widthAnimation == null)
{
widthAnimation = new DoubleAnimation
{
Duration = TimeSpan.FromSeconds(1),
From = (double)e.OldValue,
To = (double)e.NewValue
};
widthAnimation.Completed += (s, a) =>
{
widthAnimation = null;
BeginAnimation(WidthProperty, null);
};
BeginAnimation(WidthProperty, widthAnimation);
}
else
{
base.OnPropertyChanged(e);
}
}
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.
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
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();
}
}
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-