I have created fade animation for my icon, but when animation finished the icons sets back to alpha 0. How can I get him to stay in 1?
var a = new DoubleAnimation
{
From = 0.0,
To = 1.0,
FillBehavior = FillBehavior.Stop,
Duration = new Duration(TimeSpan.FromSeconds(1))
};
var storyboard = new Storyboard();
storyboard.Children.Add(a);
Storyboard.SetTarget(a, IconGlass);
Storyboard.SetTargetProperty(a, new PropertyPath(OpacityProperty));
storyboard.Begin();
}
XAML:
<StackPanel Name="IconGlass" Orientation="Horizontal" Margin="0,0,0,39" Opacity="0">
this occurs because in your StackPanel you have the Property Opacity set to 0. What you are doing is,
You have a StackPanel with Opacity 0.
You add a Animation to your StackPanel to grow up the opacity.
But after finish the animation, StackPanel will have his default value of Opacity, that is 0.
its not the best way, but you can remove Opacity="0" and Add Visibility="Collapsed"
And when you animation start put your StackPanel Visible.
IconGlass.Visibility = Visibility.Visible;
So when finishing the animation, will no desapear the StackPanel.
Know that this is not the best practise to do, but maybe one of the simplest or fastest way.
I hope this help. greetings!
Related
I am trying to use some animations to make my application feel good. But I could not help the choppy animation that no matter what I do, it is always end up stuttering.
Take a look:
DoubleAnimation anim = new DoubleAnimation()
{
//ht is height of DockPanel, I wanted to start from 200 less than Actual DockPanel Height
From = ht - 200,
To = ht,
Duration = TimeSpan.FromSeconds(1),
AccelerationRatio = 0.5,
DecelerationRatio = 0.5
};
x.BeginAnimation(HeightProperty, anim);
//x is the UserControl
Also, what I need to animate is a custom UserControl, which contains some text like 100 words and bunch of Images. I just want to make it grow in to the height of the current DockPanel as soon it is loaded.
What I saw by searching for the solution is this,
Timeline.SetDesiredFrameRate(anim, 10);
Even trying any value in there nothing really happens.
Framerate is like the frame rate of a film.
A low frame rate will give you a choppy film or a choppy animation.
Using a dockpanel is probably a bad idea for some content you are going to animate, because it will try and adjust things every time your height changes.
I suggest you go with a grid instead.
You should use a scaletransform. Partly because as you animate height you will find all the content of your usercontrol have their measures invalidated and they will want to start off the whole measure arrange cycle many times.
If you're thinking measure arrange? Then read up on how the wpf layout system works.
I would also advise you to use xaml rather than code.
Here's some code to think about:
private void StartAnimate_Click(object sender, RoutedEventArgs e)
{
var tran = testRectangle.RenderTransform = new ScaleTransform(1d, 1d)
{
CenterX = 0.5d,
CenterY = 0.5d
};
var anim = new DoubleAnimation
{
To = 1.0,
From=0,
Duration = TimeSpan.FromSeconds(0.5d),
DecelerationRatio = 0.5d,
FillBehavior = FillBehavior.Stop
};
tran.BeginAnimation(
ScaleTransform.ScaleYProperty,
anim,
HandoffBehavior.Compose);
}
I put a rectangle and my button in a dockpanel to prove this works.
<DockPanel>
<Rectangle Fill="Blue" Name="testRectangle"
Width="500"
/>
<Button Content="Animate"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Name="StartAnimate"
Click="StartAnimate_Click" />
</DockPanel>
A rectangle is pretty simple but it animates smoothly.
I'm working on application which creates a new wpf border component for each row in a database. This means I've got to style the border component in C# rather than XAML (as far as I'm aware). The styling is all good so far apart from trying to set the background opacity.
motherboards.Add(new Border());
Border moboBorder = motherboards[i];
moboBorder.Width = 150;
moboBorder.Height = 150;
moboBorder.BorderBrush = Brushes.Black;
moboBorder.Background = Brushes.White;
moboBorder.CornerRadius = new CornerRadius(10);
moboBorder.Margin = new Thickness(5);
moboBorder.BorderThickness = new Thickness(1);
You can adjust the background opacity in XAML like so
<Border BorderThickness="1" Height="100" Width="100">
<Border.BorderBrush>
<SolidColorBrush Color="Black" Opacity="0.7"/>
</Border.BorderBrush>
</Border>
But as I've said I'm creating the component in C# rather than XAML. I guess this is how you set the value in c#
moboBorder.Background.Opacity = //Value
However, I can't figure out what kind of value it takes, not just a straight up number, nothing from brushes than I can see and nothing like = new Opacity()
I've tried googling around but everything is about setting the opacity for the whole element rather than just the background of it.
A double is certainly a "straight up number"; hover the mouse over the property to see the data type.
The problem (thanks, Clemens) is that you're trying to set the opacity of Brushes.Black, which is a system object and you've got no business doing that.
But you can set the Opacity of a SolidColorBrush that you create yourself.
To create a new semi-opaque white brush:
x.Background = new SolidColorBrush(Colors.White) { Opacity = 0.5 };
See Geoff's answer for how to create a color from an RGB triplet (or ARGB quad) instead of named colors.
Or just keep the existing brush, if you're confident that you didn't get it from Brushes.
Background.Opacity = 0.5;
If you did this, you got it from System.Brushes:
<Window
Background="DeepSkyBlue"
...
If you did this, you didn't:
<Window.Background><SolidColorBrush Color="DeepSkyBlue" /></Window.Background>
That DeepSkyBlue is Colors.DeepSkyBlue; you're creating a new brush with that color.
You should be doing all of this in XAML with bindings instead of creating WPF controls in C#. You'll shoot your eye out, kid.
But it's your eye.
The equivalent of the XAML
<Border.BorderBrush>
<SolidColorBrush Color="Black" Opacity="0.7"/>
</Border.BorderBrush>
in code behind would be
moboBorder.Background = new SolidColorBrush
{
Color = Colors.Black,
Opacity = 0.7
};
In contrast to the predefined Brushes in the Brushes class (which are frozen), the above SolidColorBrush can be changed at any time later, like
moboBorder.Background.Opacity = 0.5;
As #Clemens kindly pointed out in the comments:
You can't set the Opacity of the system's shared brushes directly.
You will need to use a non-shared SolidColorBrush, and then you will be able to set the Opacity of that.
You will be able to change the Opacity from any point in the code, from thereon-in.
E.g.:
moboBorder.Background = new SolidColorBrush(Color.FromRgb(255, 0, 0))
{
Opacity = 0.5 // or whatever opacity between
// 0.0 (0%) and 1.0 (100%)
};
Or
moboBorder.Background = new SolidColorBrush(Color.FromRgb(255, 0, 0));
moboBorder.Background.Opacity = 0.5;
Similar the above example, you could also set the alpha (the opacity) if you're using RGB.
You can use the Color.FromArgb() static method, instead:
moboBorder.Background = new SolidColorBrush(Color.FromArgb(0.5, 255, 0, 0));
Just use a double between 0.0 and 1.0 (as before), as your first argument to the method.
Hope this helps.
I am using the sample on Windows UI dev labs sample gallery. And I used ShyHeader example to put in my app, but I am not using exactly the same code but I actually edited the example according to own needs.
My question is how can I use expression node to fade in a specific XAML element in correspondence to the scroll viewer, I am able to fade out an element with the scroll viewer. but I am not being able to fade in an element from opacity 0 -> opacity 1.
here is my code.
<ScrollViewer x:Name="MyScrollViewer">
<Grid>
<local:MyAdaptiveView Margin="0,300,0,0"
x:Name="AllVideosGridView"/>
<Grid x:Name="Header" Height="300" VerticalAlignment="Top">
<FlipView x:Name="MainFlipView"
</FlipView>
<Grid Background="Blue" Height="150" VerticalAlignment="Bottom" Opacity="0.5" Name="FrontGrid">
</Grid>
</Grid>
</Grid>
</ScrollViewer>
page loaded method
the only important piece of code is only at the very end of this method, the last 4, 5 lines, you can see I am able to fade out element by doing 1- progresNode but my attempt to fade in another element ( frontVisual ) by doing 0+ progressNode doesn't work and frontVisual actually remains at 0 opacity even after I scroll.
private void ShyView_Loaded(object sender, RoutedEventArgs e)
{
// Get the PropertySet that contains the scroll values from MyScrollViewer
_scrollerPropertySet = ElementCompositionPreview.GetScrollViewerManipulationPropertySet(MyScrollViewer);
_compositor = _scrollerPropertySet.Compositor;
// Create a PropertySet that has values to be referenced in the ExpressionAnimations below
_props = _compositor.CreatePropertySet();
_props.InsertScalar("progress", 0);
_props.InsertScalar("clampSize", 150);
_props.InsertScalar("scaleFactor", 0.7f);
// Get references to our property sets for use with ExpressionNodes
var scrollingProperties = _scrollerPropertySet.GetSpecializedReference<ManipulationPropertySetReferenceNode>();
var props = _props.GetReference();
var progressNode = props.GetScalarProperty("progress");
var clampSizeNode = props.GetScalarProperty("clampSize");
var scaleFactorNode = props.GetScalarProperty("scaleFactor");
// Create a blur effect to be animated based on scroll position
var blurEffect = new GaussianBlurEffect()
{
Name = "blur",
BlurAmount = 0.0f,
BorderMode = EffectBorderMode.Hard,
Optimization = EffectOptimization.Balanced,
Source = new CompositionEffectSourceParameter("source")
};
var blurBrush = _compositor.CreateEffectFactory(
blurEffect,
new[] { "blur.BlurAmount" })
.CreateBrush();
blurBrush.SetSourceParameter("source", _compositor.CreateBackdropBrush());
// Create a Visual for applying the blur effect
_blurredBackgroundImageVisual = _compositor.CreateSpriteVisual();
_blurredBackgroundImageVisual.Brush = blurBrush;
_blurredBackgroundImageVisual.Size = new Vector2((float)Header.ActualWidth, (float)Header.ActualHeight);
// Insert the blur visual at the right point in the Visual Tree
ElementCompositionPreview.SetElementChildVisual(Header, _blurredBackgroundImageVisual);
// Create and start an ExpressionAnimation to track scroll progress over the desired distance
ExpressionNode progressAnimation = EF.Clamp(-scrollingProperties.Translation.Y / clampSizeNode, 0, 1);
_props.StartAnimation("progress", progressAnimation);
// Create and start an ExpressionAnimation to animate blur radius between 0 and 15 based on progress
ExpressionNode blurAnimation = EF.Lerp(0, 15, progressNode);
_blurredBackgroundImageVisual.Brush.Properties.StartAnimation("blur.BlurAmount", blurAnimation);
// Get the backing visual for the header so that its properties can be animated
Visual headerVisual = ElementCompositionPreview.GetElementVisual(Header);
// Create and start an ExpressionAnimation to clamp the header's offset to keep it onscreen
ExpressionNode headerTranslationAnimation = EF.Conditional(progressNode < 1, 0, -scrollingProperties.Translation.Y - clampSizeNode);
headerVisual.StartAnimation("Offset.Y", headerTranslationAnimation);
// Create and start an ExpressionAnimation to scale the header during overpan
ExpressionNode headerScaleAnimation = EF.Lerp(1, 1.25f, EF.Clamp(scrollingProperties.Translation.Y / 50, 0, 1));
headerVisual.StartAnimation("Scale.X", headerScaleAnimation);
headerVisual.StartAnimation("Scale.Y", headerScaleAnimation);
//Set the header's CenterPoint to ensure the overpan scale looks as desired
headerVisual.CenterPoint = new Vector3((float)(Header.ActualWidth / 2), (float)Header.ActualHeight, 0);
// Get the backing visual for the photo in the header so that its properties can be animated
Visual photoVisual = ElementCompositionPreview.GetElementVisual(MainFlipView);
// Create and start an ExpressionAnimation to opacity fade out the image behind the header
ExpressionNode imageOpacityAnimation = 1 - progressNode;
photoVisual.StartAnimation("opacity", imageOpacityAnimation);
// Get the front visual for the photo in the header so that its properties can be animated
Visual frontVisual = ElementCompositionPreview.GetElementVisual(FrontGrid);
// Create and start an ExpressionAnimation to opacity fade out the image behind the header
ExpressionNode imageOpacityAnimation2 = 0 + progressNode;
frontVisual.StartAnimation("opacity", imageOpacityAnimation2);
}
Note the behavior I actually want is that when I scroll down then FlipView should fade out and when I scroll up to the top it should fade in, which is working perfectly, but along with it I want FrontGrid to be exactly opposite, i.e: fade in on scroll down and fade out on scroll up.
Thanks in advance
Your expression looks OK.
Note the Opacity you are animating with Composition is the Opacity of Visual. However, the Opacity of 0.5 you are setting on FrontGrid XAML is from UIElement. Doing so will break the Composition opacity expression animation.
The fix is simple - Try getting the Visual of your FrontGrid right after InitializeComponent and set its Opacity to 0.5 there (i.e. frontVisual.Opacity = 0.5) instead of setting it in XAML.
You will see this kind of "weird" behaviors starting from the Anniversary Update, due to a XAML-Composition Interop Behavior change.
For a full explanation, please read this official document.
In short, XAML doesn't know if Composition has changed the Opacity, it still thinks it should be 0.5 as it was last set. So it will try to override and cause the animation to fail. This happens to a few more properties like Offset and Size too.
My advice is if you go Composition, try going Composition all the way. :)
To learn about animation and UI, I'm making a basic WPF/C# application where a user selects the number of vehicles to display then those vehicles (ie images of different vehicles) appear in the canvas and move around.
The WPF is very simple:
<Grid>
<Canvas x:Name="MenuTabCanvas" Visibility="Visible">
<Label x:Name="AnimateDemo" Content="Animate!" HorizontalAlignment="Left" VerticalAlignment="Top" Width="104" Background="#25A0DA" Foreground="White" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Cursor="Hand" MouseDown="AnimateGrid" Canvas.Left="640" Canvas.Top="87"/>
<Canvas x:Name="AnimationCanvas" Canvas.Top="150" Canvas.Left="224" Width="814" Height="489">
</Canvas>
</Grid>
I started with a fade animation using the method described in this post and it works fine. Then I tried the translatetransform as shown below leaving the fade code in comments, and the images appear but nothing moves:
private void AnimateGrid(object sender, EventArgs e)
{
int NumberOfVehicles = 5;
var sb = new Storyboard();
for (int i = 0; i < NumberOfVehicles; i++)
{
//create & add the images to our target canvas
Image Img = getRandomVehicleImage(); //returns image of vehicle
AnimationCanvas.Children.Add(Img);
Canvas.SetTop(Img, 30 + 60 * i); //position image w/in canvas
Canvas.SetLeft(Img, 30 + 80 * i);
//add an animation
DoubleAnimation myAnimation = new DoubleAnimation()
{
// From = 0,
To = 150,
Duration = TimeSpan.FromSeconds(2),
};
Storyboard.SetTarget(myAnimation, Img);
// Storyboard.SetTargetProperty(myAnimation, new PropertyPath(Button.OpacityProperty));
Storyboard.SetTargetProperty(myAnimation, new PropertyPath(TranslateTransform.XProperty));
sb.Children.Add(myAnimation);
}
sb.Begin();
}
I have been able to get it to work with TranslateTransform.BeginAnimation but I would prefer to use the storyboard here.
Why does the translate transform behave differently than the opacity animation and what do I need to do to get it to function as intended?
By default, there is no TranslateTransform applied to a UIElement. So if you want to move an Image, you first have to set its RenderTransform property to a TranslateTransform, and then set the TargetProperty to the correct property path:
Img.RenderTransform = new TranslateTransform();
...
Storyboard.SetTargetProperty(myAnimation, new PropertyPath("RenderTransform.X"));
Alternatively, you could directly animate the TranslateTransform, even without a Storyboard:
var transform = new TranslateTransform();
Img.RenderTransform = transform;
transform.BeginAnimation(TranslateTransform.XProperty, myAnimation);
In the example below, the border has a text block and a button inside. after the button is pressed, the fadeBorder is called and the border and everything in it fades nicely. If I try to call someMethod a 2nd time, the border opacity is still 0, and I can't see my border/message/button. I tried to set it back to one by doing myBorder.Opacity=1; This does not have any effect on the opacity, it's still set to 0 after this line. Is there a trick to resetting my Border opacity back to 1.0 after a storyboard has completed? I also tried setting a double var to 1.0, then assign that var to the border opacity, that did not have an effect either.
public void someMethod(string message) {
myTextBlock.Text = message;
myStackPanel.Children.Add(myTextBlock);
Ect... with Button Control and alignment of controls
fadeBorder();
protected void fadeBorder() {
var fade = new DoubleAnimation() {
From = 1,
To = 0,
Duration = TimeSpan.FromSeconds(this.secondsToFade),
};
Storyboard.SetTarget(fade, myBorder);
Storyboard.SetTargetProperty(fade, new PropertyPath(Border.OpacityProperty));
storyBoard.Children.Add(fade);
storyBoard.Begin();
}
How to: Set a Property After Animating It with a Storyboard