I've been playing around with some basic WPF Storyboard animation and it looks quite blurry, it's Ok up to a certain speed then really degrades into blurryness.
Is there anyway I can get it to look smoother? - increase the framerate somehow or maybe double buffer the animation?
I've tried setting the objects to CacheMode="BitmapCache" but this seems to have little effect.
Does anyone have any ideas please?
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Width="1000" Height="600" >
<Window.Triggers>
<EventTrigger RoutedEvent="UserControl.Loaded" >
<BeginStoryboard>
<Storyboard RepeatBehavior="Forever">
<DoubleAnimation From="600" To="-600" Duration="00:00:02"
Storyboard.TargetName="MyObject"
Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Window.Triggers>
<Grid>
<Grid Name="MyObject">
<Grid.RenderTransform>
<TranslateTransform X="0" />
</Grid.RenderTransform>
<Ellipse Stroke="Black" Fill="Green" StrokeThickness="3" Width="100" Height="250" />
<Ellipse Stroke="Black" Fill="White" StrokeThickness="3" Width="80" Height="180" />
</Grid>
</Grid>
</Window>
You could try increasing the FrameRate:
MediaTimeline.DesiredFrameRateProperty.OverrideMetadata(typeof(System.Windows.Media.Animation.Timeline), new FrameworkPropertyMetadata(60));
The higher the number, the higher the framerate (the smoother the execution). Be cautious though, higher framerates impact performance!
I hope this helps.
Related
In one of the windows of my WPF application, the button width cannot be changed to smaller size whatever I do. I tried change the property of "width" in xaml, drag the button in designer, or pragmatically change it using c#. Even if I created a new button in that window, the width could only be changed to larger size but could not be changed to smaller size. Though there was no error or warning, none of the approaches successfully change the width. The weird thing was, I could change the height of the button smaller or larger easily by dragging, and in my other window, I can change the buttons width and height smaller or larger easily. I am using the same style for all the buttons in all the windows. If I drag the button, there will be no response of it unless I unlock the one of the litlle "knot" around it, but it will look like this:
The only thing is that I use a notification template for this window and there are some animation effects. But I didn't see any major difference between it and others. Here is the XAML code:
<Window x:Class="Timebreak.NotiWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Timebreak"
mc:Ignorable="d"
Title="TimeBreak" Height="450" Width="450"
WindowStyle="None" AllowsTransparency="True" Opacity="0.7" Background="#f9f9ff"
WindowStartupLocation="Manual" Left="0" Top="0">
<Grid>
<Button x:Name="button1" Content="OK" Margin="358,341,13,72" Click="Submit_Click" FontSize="16" VerticalAlignment="Top" HorizontalAlignment="Left"/>
<RadioButton x:Name="radioButton" Content="Yes. I want to stand up and take a break for (minutes)" HorizontalAlignment="Left" Height="26" Margin="31,105,0,0" VerticalAlignment="Top" Width="368" Checked="radioButton_Checked" FontSize="14"/>
<RadioButton x:Name="radioButton1" Content="No. I don't want to stand up and take a break because" HorizontalAlignment="Left" Margin="31,206,0,0" VerticalAlignment="Top" FontSize="14" Checked="radioButton1_Checked"/>
<Slider x:Name="slider" HorizontalAlignment="Left" Height="23" Margin="40,136,0,0" VerticalAlignment="Top" Width="374" IsSnapToTickEnabled="True" ValueChanged="slider_ValueChanged" Maximum="30" Minimum="1" Cursor="Hand" AutoToolTipPlacement="TopLeft" Interval="29" IsMoveToPointEnabled="True" TickPlacement="BottomRight"/>
<!-- Animation -->
<Grid.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)">
<SplineDoubleKeyFrame KeyTime="0:0:0" Value="0"/>
<SplineDoubleKeyFrame KeyTime="0:0:0.5" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)">
<SplineDoubleKeyFrame KeyTime="0:0:2" Value="1"/>
<SplineDoubleKeyFrame KeyTime="0:0:4" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Grid.Triggers>
<Grid.RenderTransform>
<ScaleTransform ScaleY="1" />
</Grid.RenderTransform>
</Grid>
Does ideas about it? Thanks in advance!
Does ideas about it?
You forgot to post the markup of the custom Style that you are obviously using but you could try to set the MinWidth property of the Button to 0:
<Button x:Name="button1" Content="OK" Margin="358,341,13,72" Click="Submit_Click" FontSize="16"
VerticalAlignment="Top" HorizontalAlignment="Left" MinWidth="0"/>
Please post your all relevants parts of your XAML markup and code if still cannot increase the width of the Button.
I have the following problem. I am looking to animate the color value of an icon on mouseover (and animate it back once the mouse has left). To achieve this I have created a new ColorAnimation which is triggered on MouseEnter. The property path of the animation is "(Path.Fill).(SolidColorBrush.Color)". But when running this gives the error; 'Fill' property does not point to a DependencyObject in path '(Path.Fill).(SolidColorBrush.Color)'. While I think I understand what the error means, I have no idea what property path I should use. Any ideas? Thank you in advance for your time. Please let me know if anything is left unclear.
Ps. If anyone has a better idea on how to place 'icon / path' resources I am much obliged.
Code;
ColorAnimation mouseEnterColorAnimation = new ColorAnimation {
To = Colors.Yellow,
Duration = TimeSpan.FromSeconds(1)
};
Storyboard.SetTargetName(mouseEnterColorAnimation, "DeleteIconGrid");
Storyboard.SetTargetProperty(mouseEnterColorAnimation, new PropertyPath("Path.Fill).(SolidColorBrush.Color)"));
Storyboard mouseEnterStoryboard = new Storyboard();
mouseEnterStoryboard.Children.Add(mouseEnterColorAnimation);
mouseEnterStoryboard.Begin(this);
Xaml;
<Grid x:Name="Grid" Background="Transparent" Width="100" Height="100" MouseDown="Grid_MouseDown" MouseEnter="Grid_MouseEnter" MouseLeave="Grid_MouseLeave" >
<Grid x:Name="DeleteIconGrid" Width="50" Margin="0,0,0,14"><Grid.Background><VisualBrush Visual="{StaticResource Icon-Delete}" Stretch="Uniform" /></Grid.Background></Grid>
<Label Content="Delete icon" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="6" Foreground="{DynamicResource Gray}"></Label>
</Grid>
Resources;
<Canvas x:Key="Icon-Delete" Background="Transparent">
<Path Stretch="Uniform" Fill="LightSlateGray" Data="F1 M 4.70432,0L 0.0480347,4.77802L 7.00842,11.6812L 0,18.7292L 4.70432,23.46L 11.6647,16.412L 18.6252,23.46L 23.3774,18.7774L 16.369,11.6812L 23.3294,4.77802L 18.6252,0L 11.6647,6.9986L 4.70432,0 Z" />
</Canvas>
A VisualBrush does not have a Color property... you seem to be confusing it with a SolidColorBrush. Therefore you cannot animate the colour of a VisualBrush but you can when using a SolidColorBrush.
You also have a mistake in your PropertyPath... instead of this:
"Path.Fill).(SolidColorBrush.Color)"
it should be this:
"(Path.Fill).(SolidColorBrush.Color)"
Finally, if you want to animate the Color property of a Brush then you'll need to set the Fill property to an instance of SolidColorBrush like you did in the Path in the Canvas:
<Path Stretch="Uniform" Fill="LightSlateGray" Data="F1 M 4.70432,0L 0.0480347,4.77802L 7.00842,11.6812L 0,18.7292L 4.70432,23.46L 11.6647,16.412L 18.6252,23.46L 23.3774,18.7774L 16.369,11.6812L 23.3294,4.77802L 18.6252,0L 11.6647,6.9986L 4.70432,0 Z" />
UPDATE >>>
In order to animate a VisualBrush.Visual, you will need to declare it inline. Take this example from the VisualBrush Animation page on the Visual Studio Forum:
<Button Width="320" Height="240">
<Button.Background>
<VisualBrush>
<VisualBrush.Visual>
<Canvas>
<Rectangle Width="320" Height="240" Name="myRect" Fill="Blue">
<Rectangle.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<EventTrigger.Actions>
<BeginStoryboard>
<BeginStoryboard.Storyboard>
<Storyboard >
<ColorAnimation To="Red" Duration="0:0:2" Storyboard.TargetName="myRect" Storyboard.TargetProperty="Fill.Color" AutoReverse="True" RepeatBehavior="Forever"/>
</Storyboard>
</BeginStoryboard.Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Rectangle.Triggers>
</Rectangle>
</Canvas>
</VisualBrush.Visual>
</VisualBrush>
</Button.Background>
</Button>
I am trying to create three paths (orbital paths) and get three ellipses (planets, rings) to travel along them, I have followed a few different blogs and forum posts but I cannot see why the ellipses are not travelling on the path.
Here is the xaml:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
ResizeMode="NoResize"
Title="Window2" Width="800" Height="600">
<Window.Resources>
<PathGeometry x:Key="smallGeo" Figures="M 400,250C 427.614,250 450,272.386 450,300C 450,327.614 427.614,350 400,350C 372.386,350 350,327.614 350,300C 350,272.386 372.386,250 400,250"/>
<PathGeometry x:Key="mediumGeo" Figures="M 400,245C 430.376,245 455,269.624 455,300C 455,330.376 430.376,355 400,355C 369.624,355 345,330.376 345,300C 345,269.624 369.624,245 400,245"/>
<PathGeometry x:Key="largeGeo" Figures="M 400,240C 433.137,240 460,266.863 460,300C 460,333.137 433.137,360 400,360C 366.863,360 340,333.137 340,300C 340,266.863 366.863,240 400,240"/>
</Window.Resources>
<Grid Width="800" Height="600" HorizontalAlignment="Center" VerticalAlignment="Center">
<Canvas>
<Canvas.Triggers>
<EventTrigger RoutedEvent="Canvas.Loaded">
<BeginStoryboard>
<Storyboard>
<!-- Small orbit animation -->
<DoubleAnimationUsingPath
Storyboard.TargetName="smallEllipse"
Storyboard.TargetProperty="(Canvas.Left)"
PathGeometry="{StaticResource smallGeo}"
Duration="0:0:5"
RepeatBehavior="Forever"
Source="X"/>
<DoubleAnimationUsingPath
Storyboard.TargetName="smallEllipse"
Storyboard.TargetProperty="(Canvas.Top)"
PathGeometry="{StaticResource smallGeo}"
Duration="0:0:5"
RepeatBehavior="Forever"
Source="Y"/>
<!-- Medium orbit animation -->
<DoubleAnimationUsingPath
Storyboard.TargetName="mediumEllipse"
Storyboard.TargetProperty="(Canvas.Left)"
PathGeometry="{StaticResource mediumGeo}"
Duration="0:0:5"
RepeatBehavior="Forever"
Source="X"/>
<DoubleAnimationUsingPath
Storyboard.TargetName="mediumEllipse"
Storyboard.TargetProperty="(Canvas.Top)"
PathGeometry="{StaticResource mediumGeo}"
Duration="0:0:5"
RepeatBehavior="Forever"
Source="Y"/>
<!-- Large orbit animation -->
<DoubleAnimationUsingPath
Storyboard.TargetName="largeEllipse"
Storyboard.TargetProperty="(Canvas.Left)"
PathGeometry="{StaticResource largeGeo}"
Duration="0:0:5"
RepeatBehavior="Forever"
Source="X"/>
<DoubleAnimationUsingPath
Storyboard.TargetName="largeEllipse"
Storyboard.TargetProperty="(Canvas.Top)"
PathGeometry="{StaticResource largeGeo}"
Duration="0:0:5"
RepeatBehavior="Forever"
Source="Y"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Canvas.Triggers>
<Ellipse x:Name="smallEllipse" Height="20" Stroke="Green" StrokeThickness="5" Width="20" RenderTransformOrigin="0.5,0.5"/>
<Ellipse x:Name="mediumEllipse" Height="40" Stroke="Red" StrokeThickness="5" Width="40" RenderTransformOrigin="0.5,0.5"/>
<Ellipse x:Name="largeEllipse" Height="60" Stroke="Blue" StrokeThickness="5" Width="60" RenderTransformOrigin="0.5,0.5"/>
<Path Stroke="Green" Data="{StaticResource smallGeo}"/>
<Path Stroke="Red" Data="{StaticResource mediumGeo}"/>
<Path Stroke="Blue" Data="{StaticResource largeGeo}"/>
</Canvas>
</Grid>
I used MS expression design to create the paths and kaxaml to preview the xaml.
I suspect that the Animation is not taking into account the Size of the Ellipse as its animating using the Top/Left of the Ellipse not the center of the Ellipse
One way around this would be to set the Margin of the Ellipse to negative half of the Size
Example:
<Ellipse x:Name="smallEllipse" Margin="-10" Height="20" Width="20" ......./>
<Ellipse x:Name="mediumEllipse" Margin="-20" Height="40" Width="40" ......./>
<Ellipse x:Name="largeEllipse" Margin="-30" Height="60" Width="60" ......../>
Result:
Before: After :
I have implemented the animation of moving of a grid control in the following manner:
<Grid
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.Style>
<Style TargetType="Grid">
<Style.Triggers>
<DataTrigger
Binding="{Binding ElementName=rootLayout, Path=IsVisible}"
Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ThicknessAnimation
Storyboard.TargetProperty="Margin"
From="-500,0,0,0"
To="0,0,0,0"
Duration="0:0:0.5" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Style>
<Border
Grid.RowSpan="2"
Background="Black"
CornerRadius="6" >
<Border.Effect>
<DropShadowEffect />
</Border.Effect>
</Border>
<TextBlock
Grid.Row="0"
Width="400"
Height="200"
Margin="20,20,20,10"
Text="{Binding Path=MessageText}" />
<Button
Grid.Row="1"
Margin="20,5,20,15"
HorizontalAlignment="Right"
Width="75"
Content="OK"
Command="{Binding Path=CloseDialogCommand}" />
</Grid>
The animation works fine, but it's ugly. It is shaky / jittery / jerky and it really looks unprofessional. Is there a way to improve this? Am I using the right approach with animating the value change on the Margin property in order to move the grid? I've read about RenderTransform, but I don't know how to use it in my case.
Also, the animation looks unnatural. I know this can be improved but I don't know how. What are these properties and can they help me enhance my animation:
AccelerationRatio
DecelerationRatio
EasingFunction
IsAdditive
IsCumulative
SpeedRatio
Thanks for helping!
P.S. I am trying to put as much code as possible in XAML, so I'd prefer that approach, but really, if there's anything to improve this...
Use easing functions, a simple DoubleAnimation and RenderTransform, e.g.
<Button Content="Test">
<Button.RenderTransform>
<TranslateTransform/>
</Button.RenderTransform>
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="RenderTransform.X"
From="-500" To="0">
<DoubleAnimation.EasingFunction>
<CubicEase EasingMode="EaseOut"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
This should be quite smooth, check out this overview on easing functions to get an idea of how they affect the animation.
Also note that the duration has a strong effect on what an animation looks like, depending on what easing function you use setting high duration values is needed because they slow down significantly at the end.
i'm new to wpf and i'm try to learn something.
My problem is : i need to bind all that i want to a looping animation...
Example:
<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<StackPanel>
<Slider Visibility="Hidden" Minimum="0" Maximum="100" Height="22" Margin="73,40,105,0" Name="Slider1" VerticalAlignment="Top" Value="0">
<Slider.Triggers>
<EventTrigger RoutedEvent="Slider.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="Slider1"
Storyboard.TargetProperty="Value"
From="0" To="100" Duration="0:0:5"
AutoReverse="True" RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Slider.Triggers>
</Slider>
<Slider Minimum="0" Maximum="100" Height="22" Margin="72,98,106,0" Name="Slider2" VerticalAlignment="Top" Value="{Binding ElementName=Slider1, Path=Value}"/>
<Button Width="{Binding ElementName=Slider1, Path=Value}"></Button>
</StackPanel>
Slider1 is hidden and act as a Source for Slider2 and ButtonWidth.
Like a standalone oscillator.
I need a way to eliminate slider1 and bind directly to a standalone animation that loops.
It is possible?
Thanks in advance :)
Why don't you simply animate the Slider2 Value the same way you've animated Slider1's value? You can also animate the Button's Width. I am not sure why you would need Slider1 in the first place. The following markup demonstrates removing Slider1 and using the animation as a resource:
<Window.Resources>
<DoubleAnimation x:Key="ValueAnimation"
Storyboard.TargetProperty="Value"
From="0" To="100" Duration="0:0:5"
AutoReverse="True" RepeatBehavior="Forever" />
</Window.Resources>
<StackPanel>
<Slider Minimum="0" Maximum="100" Height="22" Margin="72,98,106,0"
Name="Slider2" VerticalAlignment="Top">
<Slider.Triggers>
<EventTrigger RoutedEvent="Slider.Loaded">
<BeginStoryboard>
<Storyboard Storyboard.TargetName="Slider2">
<StaticResource ResourceKey="ValueAnimation"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Slider.Triggers>
</Slider>
<Button Width="{Binding ElementName=Slider2, Path=Value}"/>
</StackPanel>
You could remove the TargetProperty from ValueAnimation and specify that per animation, as well. That would let you use a single animation for both the Button.Width and the Slider.Value.
thanks for your answer :)
Why don't you simply animate the Slider2 Value the same way you've animated Slider1's value?
because i need to centralize the animation values to share it on multiple objects (not only another slider) and, in this way, i can edit values in 1 place only :)
Thank you your example fits well :)