I'm trying to recreate the slide-up part animation of the notification-queue on Windows 10 live tiles with an image I have ontop of another image. Below I have a "slide-up" storyboard working...but it's not the same.
Is the live tile ani actually growing in height as it slides up over the first?
I can't "see/figure" what it's doing.
public static async Task SlideUp(FrameworkElement element, double duration, int to = 0)
{
var tempTransform = new TranslateTransform();
element.RenderTransform = tempTransform;
var animation = new DoubleAnimation
{
From = element.ActualHeight * 2,
To = to,
Duration = TimeSpan.FromSeconds(duration),
EasingFunction = new CubicEase { EasingMode = EasingMode.EaseOut }
};
Storyboard.SetTargetProperty(animation, "Y");
Storyboard.SetTarget(animation, tempTransform);
var sb = new Storyboard();
sb.Duration = animation.Duration;
sb.Children.Add(animation);
await sb.BeginAsync();
}
The flip part of the animations would be nice too.
You could take a look at the DoubleAnimationUsingKeyFrames class:
https://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.media.animation.doubleanimationusingkeyframes.aspx
Update: You can also animate the Height of the image
public static async Task SlideUp(FrameworkElement element, double duration, int to = 0)
{
var trTransform = new TranslateTransform();
element.RenderTransform = trTransform;
double from = element.ActualHeight;
duration *= 1.5;
var animation = new DoubleAnimationUsingKeyFrames();
animation.KeyFrames.Add(new DiscreteDoubleKeyFrame
{
KeyTime = KeyTime.FromTimeSpan(new TimeSpan(0,0,0,0)),
Value = from / 2
});
var ks = new KeySpline { ControlPoint1 = new Point(0.0, 0.0), ControlPoint2 = new Point(0.9, 0.1) };
animation.KeyFrames.Add(new SplineDoubleKeyFrame
{
KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(duration*1000/2)),
KeySpline = ks,
Value = (from - to) / 3 + to
});
var ks2 = new KeySpline { ControlPoint1 = new Point(0.1, 0.9), ControlPoint2 = new Point(0.2, 1.0) };
animation.KeyFrames.Add(new SplineDoubleKeyFrame
{
KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(duration)),
KeySpline = ks2,
Value = to
});
Storyboard.SetTargetProperty(animation, "Y");
Storyboard.SetTarget(animation, trTransform);
var sb = new Storyboard();
sb.Duration = animation.Duration;
sb.Children.Add(animation);
DoubleAnimationUsingKeyFrames resizeHeightAnimation = new DoubleAnimationUsingKeyFrames()
{
EnableDependentAnimation = true
};
resizeHeightAnimation.KeyFrames.Add(new DiscreteDoubleKeyFrame
{
KeyTime = KeyTime.FromTimeSpan(new TimeSpan(0, 0, 0, 0)),
Value = 0
});
var heightSpline1 = new KeySpline { ControlPoint1 = new Point(0.0, 0.0), ControlPoint2 = new Point(0.9, 0.1) };
resizeHeightAnimation.KeyFrames.Add(new SplineDoubleKeyFrame
{
KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(duration * 1000 / 2)),
KeySpline = heightSpline1,
Value = from / 3
});
var heightSpline2 = new KeySpline { ControlPoint1 = new Point(0.1, 0.9), ControlPoint2 = new Point(0.2, 1.0) };
resizeHeightAnimation.KeyFrames.Add(new SplineDoubleKeyFrame
{
KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(duration)),
KeySpline = heightSpline2,
Value = from
});
Storyboard.SetTarget(resizeHeightAnimation, element);
Storyboard.SetTargetProperty(resizeHeightAnimation, "RenderTransform.Height");
sb.Children.Add(resizeHeightAnimation);
sb.Begin();
}
If that looks to laggy for you, you can also try setting the VerticalAlignment of the element to Bottom and remove the position animation part of the method.
Related
In this Application, i have a car class with a method called Spawn (which should draw the object on a Canvas which i defined in the XAML file). I call the Method in MainWindow, but when I run my program, there is no car being drawn onto the Canvas.
Here is the Spawn method:
public void Spawn(Canvas cvs)
{
cvs = new Canvas();
cvs.Children.Clear();
carBody.Width = 70;
carBody.Height = 120;
carBody.Background = new SolidColorBrush(Color);
Canvas.SetLeft(carBody, SpawnLocation.X);
Canvas.SetTop(carBody, SpawnLocation.Y);
Rectangle[] tires = new Rectangle[4];
Rectangle[] windows = new Rectangle[2];
Label lblBrand = new Label();
RotateTransform rotation = new RotateTransform();
// Reifen
tires[0] = new Rectangle()
{
Fill = Brushes.Black,
Width = 20,
Height = 30
};
Canvas.SetLeft(tires[0], -9);
Canvas.SetTop(tires[0], 18);
tires[1] = new Rectangle()
{
Fill = Brushes.Black,
Width = 20,
Height = 30
};
Canvas.SetLeft(tires[1], 61);
Canvas.SetTop(tires[1], 18);
tires[2] = new Rectangle()
{
Fill = Brushes.Black,
Width = 20,
Height = 30
};
Canvas.SetLeft(tires[2], -9);
Canvas.SetTop(tires[2], 80);
tires[3] = new Rectangle()
{
Fill = Brushes.Black,
Width = 20,
Height = 30
};
Canvas.SetLeft(tires[3], 61);
Canvas.SetTop(tires[3], 80);
// Fenster
windows[0] = new Rectangle() // Front
{
Fill = Brushes.White,
Width = 50,
Height = 40
};
Canvas.SetLeft(windows[0], 0);
Canvas.SetTop(windows[0], 0);
windows[1] = new Rectangle() // rear
{
Fill = Brushes.White,
Width = 50,
Height = 50
};
Canvas.SetLeft(windows[1], 0);
Canvas.SetTop(windows[1], 0);
// Label Automarke
lblBrand.Width = 40;
lblBrand.Height = 23;
lblBrand.Content = Brand;
// Add2Canvas
for (int i = 0; i < tires.Length; i++)
carBody.Children.Add(tires[i]);
for (int i = 0; i < windows.Length; i++)
carBody.Children.Add(windows[i]);
carBody.Children.Add(lblBrand);
if (Direction == "nord")
{
rotation.Angle = 0;
rotation.CenterX = SpawnLocation.X;
rotation.CenterY = SpawnLocation.Y;
carBody.RenderTransform = rotation;
}
else if (Direction == "süd")
{
rotation.Angle = 180;
rotation.CenterX = SpawnLocation.X;
rotation.CenterY = SpawnLocation.Y;
carBody.RenderTransform = rotation;
}
else if (Direction == "west")
{
rotation.Angle = 90;
rotation.CenterX = SpawnLocation.X;
rotation.CenterY = SpawnLocation.Y;
carBody.RenderTransform = rotation;
}
else if (Direction == "ost")
{
rotation.Angle = 270;
rotation.CenterX = SpawnLocation.X;
rotation.CenterY = SpawnLocation.Y;
carBody.RenderTransform = rotation;
}
cvs.Children.Add(carBody);
}
Calling the methodMainWindow:
Car car1;
public MainWindow()
{
InitializeComponent();
car1 = new Car("Audi", Colors.Red);
car1.Direction = "west";
car1.SpawnLocation = new Point(550, 340);
car1.Spawn(gameScreen);
}
Thanks in advance!
Fixed it! I initialized the argmument of my Spawn method, it now works after I deleted it.
My method looked like this first:
public void Spawn(Canvas cvs)
{
cvs = new Canvas();
cvs.Children.Clear();
carBody.Width = 70;
I initialized my the Argument, but since i don't wanna create a new Canvas, i deleted these two first lines of my method.
public void Spawn(Canvas cvs)
{
carBody.Width = 70;
carBody.Height = 120;
carBody.Background = new SolidColorBrush(Color);
Now its working fine.
I'm trying to create implicit hide and show animations that contain a blur. I have the following code to do a Gaussian Blur animation, but I don't know how to add it to a CompositionAnimationGroup and use it as an implicit animation. I only know how to start an animation using the SpriteVisual.
public static void CompositionAnimationBlur(UIElement element, int durationMilliseconds)
{
var visual = ElementCompositionPreview.GetElementVisual(element);
var compositor = visual.Compositor;
var effect = new GaussianBlurEffect()
{
Name = "Blur",
Source = new CompositionEffectSourceParameter("EffectSource"),
BlurAmount = 0f,
BorderMode = EffectBorderMode.Hard,
};
var blurEffectFactory = compositor.CreateEffectFactory(effect, new[] { effect.Name + "." + nameof(effect.BlurAmount) });
var brush = blurEffectFactory.CreateBrush();
var destinationBrush = compositor.CreateBackdropBrush();
brush.SetSourceParameter("EffectSource", destinationBrush);
var sprite = compositor.CreateSpriteVisual();
sprite.Size = new Vector2((float)(element.RenderSize.Width), (float)(element.RenderSize.Height));
sprite.Brush = brush;
var anim = compositor.CreateScalarKeyFrameAnimation();
anim.InsertKeyFrame(0.0f, 0f);
anim.InsertKeyFrame(1.0f, 50f);
anim.Duration = TimeSpan.FromMilliseconds(durationMilliseconds);
ElementCompositionPreview.SetElementChildVisual(element, sprite);
sprite.Brush.Properties.StartAnimation("Blur.BlurAmount", anim);
}
For you scenario, although you could add blur animation to CompositionAnimationGroup like the following, you can not start AnimationGroup in the element visual correctly. Because the blur animation apply to the sprite brush and the fade animation apply to element visual.
public static void CompositionAnimationBlur(UIElement element, int durationMilliseconds)
{
var visual = ElementCompositionPreview.GetElementVisual(element);
var compositor = visual.Compositor;
var AnimationGroup = compositor.CreateAnimationGroup();
var effect = new GaussianBlurEffect()
{
Name = "Blur",
Source = new CompositionEffectSourceParameter("EffectSource"),
BlurAmount = 0f,
BorderMode = EffectBorderMode.Hard,
};
var blurEffectFactory = compositor.CreateEffectFactory(effect, new[] { effect.Name + "." + nameof(effect.BlurAmount) });
var brush = blurEffectFactory.CreateBrush();
var destinationBrush = compositor.CreateBackdropBrush();
brush.SetSourceParameter("EffectSource", destinationBrush);
var sprite = compositor.CreateSpriteVisual();
sprite.Size = new Vector2((float)(element.RenderSize.Width), (float)(element.RenderSize.Height));
sprite.Brush = brush;
var anim = compositor.CreateScalarKeyFrameAnimation();
anim.InsertKeyFrame(0.0f, 0f);
anim.InsertKeyFrame(1.0f, 50f);
anim.Target = "Blur.BlurAmount";
anim.Duration = TimeSpan.FromMilliseconds(durationMilliseconds);
ElementCompositionPreview.SetElementChildVisual(element, sprite);
AnimationGroup.Add(anim);
sprite.Brush.Properties.StartAnimationGroup(AnimationGroup);
}
I suggest that you could use UWP Community Toolkit to integrate fade and blur animations.
await MyRec.Blur(value: 10, duration: 1000, delay: 0).Fade(value: 0.0f, duration: 1000, delay: 0).StartAsync();
What I'm trying to do is make my control "pulse" (as in enlarge a bit, then shrink a bit, then back to its normal size). The following code does exactly what I want, but it just seems like there should be a simpler way. It has to be done in code behind because this is an abstract class that most of our controls derive from. I don't have much experience with animation controls and story boards.
So specifically my question is, is there a simpler way to get the desired results than the following method (while still being done in the code-behind)?
public void Pulse()
{
var storyboard = new Storyboard
{
FillBehavior = FillBehavior.Stop,
RepeatBehavior = new RepeatBehavior(2)
};
double timeIncrement = .15;
double changePercent = 20;
var firstTime = TimeSpan.FromSeconds(timeIncrement);
var secondTime = TimeSpan.FromSeconds(timeIncrement * 3);
var thirdTime = TimeSpan.FromSeconds(timeIncrement * 4);
var scale = new ScaleTransform(1.0, 1.0);
RenderTransformOrigin = new Point(.5, .5);
RenderTransform = scale;
//enlarge
{
DoubleAnimation growX = new DoubleAnimation
{
Duration = firstTime,
To = 1 + changePercent
};
storyboard.Children.Add(growX);
Storyboard.SetTargetProperty(growX, new PropertyPath("RenderTransform.ScaleX"));
DoubleAnimation growY = new DoubleAnimation
{
Duration = firstTime,
To = 1 + changePercent
};
storyboard.Children.Add(growY);
Storyboard.SetTargetProperty(growY, new PropertyPath("RenderTransform.ScaleY"));
}
//shrink
{
DoubleAnimation shrinkX = new DoubleAnimation
{
Duration = secondTime,
To = 1 - changePercent
};
storyboard.Children.Add(shrinkX);
Storyboard.SetTargetProperty(shrinkX, new PropertyPath("RenderTransform.ScaleX"));
DoubleAnimation shrinkY = new DoubleAnimation
{
Duration = secondTime,
To = 1 - changePercent
};
storyboard.Children.Add(shrinkY);
Storyboard.SetTargetProperty(shrinkY, new PropertyPath("RenderTransform.ScaleY"));
}
//back to normal
{
DoubleAnimation normX = new DoubleAnimation
{
Duration = thirdTime,
To = 1
};
storyboard.Children.Add(normX);
Storyboard.SetTargetProperty(normX, new PropertyPath("RenderTransform.ScaleX"));
DoubleAnimation normY = new DoubleAnimation
{
Duration = thirdTime,
To = 1
};
storyboard.Children.Add(normY);
Storyboard.SetTargetProperty(normY, new PropertyPath("RenderTransform.ScaleY"));
}
BeginStoryboard(storyboard, HandoffBehavior.SnapshotAndReplace, false);
}
You could perhaps simplify things a little by moving your grow/shrink logic into its own method. This reduces duplication and provides a potentially more reusable code kibble.
public void Pulse()
{
var storyboard = new Storyboard
{
FillBehavior = FillBehavior.Stop,
RepeatBehavior = new RepeatBehavior(2)
};
double timeIncrement = .15;
double growPercent = 20;
double shrinkPercent = -20;
var firstTime = TimeSpan.FromSeconds(timeIncrement);
var secondTime = TimeSpan.FromSeconds(timeIncrement * 3);
var thirdTime = TimeSpan.FromSeconds(timeIncrement * 4);
var scale = new ScaleTransform(1.0, 1.0);
RenderTransformOrigin = new Point(.5, .5);
RenderTransform = scale;
storyboard = AddSizeChange(firstTime, growPercent, storyboard);
storyboard = AddSizeChange(secondTime, shrinkPercent, storyboard);
storyboard = AddSizeChange(thirdTime, growPercent, storyboard);
BeginStoryboard(storyboard, HandoffBehavior.SnapshotAndReplace, false);
}
public Storyboard AddSizeChange(TimeSpan animTime, double changePercent, Storyboard storyboard)
{
DoubleAnimation growX = new DoubleAnimation
{
Duration = animTime,
To = 1 + changePercent
};
storyboard.Children.Add(growX);
Storyboard.SetTargetProperty(growX, new PropertyPath("RenderTransform.ScaleX"));
DoubleAnimation growY = new DoubleAnimation
{
Duration = animTime,
To = 1 + changePercent
};
storyboard.Children.Add(growY);
Storyboard.SetTargetProperty(growY, new PropertyPath("RenderTransform.ScaleY"));
return storyboard;
}
That's a fine way of doing it, WPF does not provide methods or events to automatically pulse. Yours is simple and as you've created it, you know how to modify it as you wish.
I am trying to get these ellipses to grow but I cannot figure out how to start the animation. This is my first attempt at WPF animation and I don't quite understand how it all works.
private void drawEllipseAnimation(double x, double y)
{
StackPanel myPanel = new StackPanel();
myPanel.Margin = new Thickness(10);
Ellipse e = new Ellipse();
e.Fill = Brushes.Yellow;
e.Stroke = Brushes.Black;
e.Height = 0;
e.Width = 0;
e.Opacity = .8;
canvas2.Children.Add(e);
Canvas.SetLeft(e, x);
Canvas.SetTop(e, y);
DoubleAnimation myDoubleAnimation = new DoubleAnimation();
myDoubleAnimation.From = 0;
myDoubleAnimation.To = 10;
myDoubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(5));
myStoryboard = new Storyboard();
myStoryboard.Children.Add(myDoubleAnimation);
Storyboard.SetTargetName(myDoubleAnimation, e.Name);
Storyboard.SetTargetProperty(myDoubleAnimation, new PropertyPath(Ellipse.HeightProperty));
Storyboard.SetTargetProperty(myDoubleAnimation, new PropertyPath(Ellipse.WidthProperty));
}
You don't need a Storyboard here. Just do
e.BeginAnimation(Ellipse.WidthProperty, myDoubleAnimation);
e.BeginAnimation(Ellipse.HeightProperty, myDoubleAnimation);
If you really need to do it with a Storyboard, you will have to add separate animations, one per animated property, to the Storyboard. And you have to call SetTarget instead of SetTargetName when you don't apply a name. Finally you'll need to start the Storyboard by calling Begin:
DoubleAnimation widthAnimation = new DoubleAnimation
{
From = 0,
To = 10,
Duration = TimeSpan.FromSeconds(5)
};
DoubleAnimation heightAnimation = new DoubleAnimation
{
From = 0,
To = 10,
Duration = TimeSpan.FromSeconds(5)
};
Storyboard.SetTargetProperty(widthAnimation, new PropertyPath(Ellipse.WidthProperty));
Storyboard.SetTarget(widthAnimation, e);
Storyboard.SetTargetProperty(heightAnimation, new PropertyPath(Ellipse.HeightProperty));
Storyboard.SetTarget(heightAnimation, e);
Storyboard s = new Storyboard();
s.Children.Add(widthAnimation);
s.Children.Add(heightAnimation);
s.Begin();
I have the following code:
private void Package_ContactDown(object sender, ContactEventArgs e)
{
ScatterViewItem svi = new ScatterViewItem();
svi.Orientation = 0;
removeShadow(svi);
svi.IsActive = true;
PackageView view = new PackageView(sourceFile, this);
view.setScatterViewItem(svi);
svi.Width = 1024;
svi.Height = 768;
svi.Center = new Point(512, 384);
Viewbox box = new Viewbox();
box.Name = "box";
box.Child = view;
this.RegisterName(box.Name, box);
Viewbox boxSmall = new Viewbox();
boxSmall.Name = "boxSmall";
this.RegisterName(boxSmall.Name, boxSmall);
TextBlock txt = new TextBlock();
txt.Foreground = Brushes.White;
txt.Text = "Package of class";
boxSmall.Child = txt;
boxSmall.Opacity = 0;
boxSmall.IsHitTestVisible = false;
Rectangle border = new Rectangle();
border.Name = "border";
this.RegisterName(border.Name, border);
border.Fill = Brushes.Transparent;
border.Stroke = Brushes.White;
border.StrokeThickness = 2;
border.Opacity = 0;
Grid g = new Grid();
g.Background = this.FindResource("WindowBackground") as ImageBrush;
g.Children.Add(box);
g.Children.Add(boxSmall);
g.Children.Add(border);
svi.Content = g;
window.IconDisplay.Items.Add(svi);
DoubleAnimation animation = new DoubleAnimation();
animation.From = 0.0;
animation.To = 1.0;
animation.Duration = new Duration(TimeSpan.FromSeconds(3));
animation.AutoReverse = false;
Storyboard storyboard = new Storyboard();
storyboard.Children.Add(animation);
Storyboard.SetTargetName(animation, boxSmall.Name);
Storyboard.SetTargetProperty(animation, new PropertyPath(Viewbox.OpacityProperty));
DoubleAnimation animation2 = new DoubleAnimation();
animation2.From = 1.0;
animation2.To = 0.0;
animation2.Duration = new Duration(TimeSpan.FromSeconds(3));
animation2.AutoReverse = false;
Storyboard storyboard2 = new Storyboard();
storyboard2.Children.Add(animation2);
Storyboard.SetTargetName(animation2, box.Name);
Storyboard.SetTargetProperty(animation2, new PropertyPath(Viewbox.OpacityProperty));
DoubleAnimation animation3 = new DoubleAnimation();
animation3.From = 0.0;
animation3.To = 1.0;
animation3.Duration = new Duration(TimeSpan.FromSeconds(3));
animation3.AutoReverse = false;
Storyboard storyboard3 = new Storyboard();
storyboard3.Children.Add(animation3);
Storyboard.SetTargetName(animation3, border.Name);
Storyboard.SetTargetProperty(animation3, new PropertyPath(Rectangle.OpacityProperty));
svi.SizeChanged += delegate(object s, SizeChangedEventArgs args)
{
if (args.NewSize.Width < 150 && args.NewSize.Height < 150 && !isSmall)
{
svi.CanScale = false;
storyboard.Begin(this);
storyboard2.Begin(this);
storyboard3.Begin(this);
storyboard3.Completed += delegate(object sender2, EventArgs args2)
{
Console.WriteLine("Storyboard completed");
svi.CanScale = true;
};
isSmall = true;
}
if (args.NewSize.Width > 150 && args.NewSize.Height > 150 && isSmall)
{
isSmall = false;
}
};
}
And I noticed that the Storyboard#completed Event is never triggered. Why? And an additional question... Is there any way to reverse all these 3 animations? If I want to display the animations the other way round?
The completed event will not fire the first time around because it is not set before you call the begin method. Set the completed handler then call the begin and you should see the handler get called.
Is there a reason that you have three storyboards? Storyboards can contain multiple animations and you could just put all the animations into one storyboard. This would simplify reversing the storyboard.
DoubleAnimation animation = new DoubleAnimation();
animation.From = 0.0;
animation.To = 1.0;
animation.Duration = new Duration(TimeSpan.FromSeconds(3));
animation.AutoReverse = false;
DoubleAnimation animation2 = new DoubleAnimation();
animation2.From = 1.0;
animation2.To = 0.0;
animation2.Duration = new Duration(TimeSpan.FromSeconds(3));
animation2.AutoReverse = false;
DoubleAnimation animation3 = new DoubleAnimation();
animation3.From = 0.0;
animation3.To = 1.0;
animation3.Duration = new Duration(TimeSpan.FromSeconds(3));
animation3.AutoReverse = false;
Storyboard storyboard = new Storyboard();
storyboard.AutoReverse = true;
storyboard.Children.Add(animation);
Storyboard.SetTargetName(animation, boxSmall.Name);
Storyboard.SetTargetProperty(animation, new PropertyPath(Viewbox.OpacityProperty));
storyboard.Children.Add(animation2);
Storyboard.SetTargetName(animation2, box.Name);
Storyboard.SetTargetProperty(animation2, new PropertyPath(Viewbox.OpacityProperty));
storyboard.Children.Add(animation3);
Storyboard.SetTargetName(animation3, border.Name);
Storyboard.SetTargetProperty(animation3, new PropertyPath(Rectangle.OpacityProperty));
svi.SizeChanged += delegate(object s, SizeChangedEventArgs args)
{
if (args.NewSize.Width < 150 && args.NewSize.Height < 150 && !isSmall)
{
svi.CanScale = false;
storyboard.Completed += (o, s) =>
{
Console.WriteLine("Storyboard completed");
svi.CanScale = true;
};
storyboard.Begin(this);
isSmall = true;
}
if (args.NewSize.Width > 150 && args.NewSize.Height > 150 && isSmall)
{
isSmall = false;
}
};