WPF 3D object rotating continuously - c#

I am using SplineRotation3DKeyFrame to rotate my 3D object continuously.
But the behavior is somehow queer:
1. there must be two SplineRotation3DKeyFrame inside Rotation3DAnimationUsingKeyFrames, or there will be not animation.
2. it seems the rotation is not continuous. there is always an abrupt movement every period.
And I want to make it rotate at some speed, for example 30 round per minute.
Could any give me some advice how to setup the animation code?
Thanks in advance.
Ting
here is my code (excluding 3D data)
Storyboard.TargetName="World"
Storyboard.TargetProperty="(ModelVisual3D.Transform).(Transform3DGroup.Children)[0].(RotateTransform3D.Rotation)"
Duration="00:00:02"
AutoReverse="False">
<SplineRotation3DKeyFrame KeyTime="00:00:02">
<SplineRotation3DKeyFrame.Value >
<AxisAngleRotation3D Angle="180" Axis="0,0,1"/>
</SplineRotation3DKeyFrame.Value>
</SplineRotation3DKeyFrame>
<SplineRotation3DKeyFrame KeyTime="00:00:04">
<SplineRotation3DKeyFrame.Value>
<AxisAngleRotation3D Angle="359" Axis="0,0,1"/>
</SplineRotation3DKeyFrame.Value>
</SplineRotation3DKeyFrame>
</Rotation3DAnimationUsingKeyFrames>
</Storyboard>
</UserControl.Resources>
<UserControl.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard Storyboard="{StaticResource RotateStoryboard}"/>
</EventTrigger>
</UserControl.Triggers>
<Grid>
<Viewport3D ClipToBounds="True" Margin="21,15,10,28">
<Viewport3D.Camera>
<OrthographicCamera FarPlaneDistance="291.04190202230194" LookDirection="0,-30,0" NearPlaneDistance="0.1" Position="0,30,0" UpDirection="0,0,-1" Width="50"/>
</Viewport3D.Camera>
<ModelVisual3D x:Name="World">
<ModelVisual3D.Transform> <!-- tinger -->
<Transform3DGroup>
<RotateTransform3D/>
</Transform3DGroup>
</ModelVisual3D.Transform>

Related

How to do flashing rectangle outline for a WPF datagrid cell?

Basically I have a WPF datagrid, and I want to add a flashing outline to a specific cell in XAML via binding that will make this visible. I know how to do this except the flashing part.
How can I do that so that the rectangle outline flashes for a specific duration like 2 seconds, so it goes from opacity = 0 to 1 and then 0 and so on.
Does WPF have a mechanism for this?
<Border BorderThickness="1" BorderBrush="Red">
<Rectangle Fill="#FF5A9AE0"
Stretch="UniformToFill"
ClipToBounds="True"/>
</Border>
This will flash the border on and off.
<Border Name="MyBorder" BorderThickness="1" BorderBrush="Red">
<Border.Triggers>
<EventTrigger RoutedEvent="Border.Loaded">
<BeginStoryboard>
<Storyboard>
<ThicknessAnimationUsingKeyFrames
Storyboard.TargetName="MyBorder"
Storyboard.TargetProperty="BorderThickness"
AutoReverse="True" RepeatBehavior="Forever">
<DiscreteThicknessKeyFrame KeyTime="0:0:00.00" Value="1" />
<DiscreteThicknessKeyFrame KeyTime="0:0:00.25" Value="5" />
<DiscreteThicknessKeyFrame KeyTime="0:0:00.50" Value="1" />
</ThicknessAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Border.Triggers>
<Rectangle Fill="#FF5A9AE0" Stretch="UniformToFill" ClipToBounds="True" />
</Border>
There are lots of animation options, so please have a look at https://learn.microsoft.com/en-us/dotnet/desktop/wpf/graphics-multimedia/animation-overview?view=netframeworkdesktop-4.8 for details/ideas.

Dynamically move object on canvas

Scenario as follows.
I have an canvas on which I want to move, lets say an rectangel, across the screen. The way the rectangle is supposed to move is determined by one specific path (like a railway, the rectangle is supposed to only move on the rails). The position on which the rectangle is currently located is provided by external source.
Current Location is provided every ~200-500ms.
So far I have tried the following:
simple TranslateTransform. Does the trick, but the rectangle jumps from Point a to b. No smooth Translation.
Storyboard with a doubleAnimation
Smoother, but the rectangle doesn´t follow the required path.
DoubleAnimationUsingPath. Rectangle is moving on the path. But now I am not able to provide the current position by external source.
Easiest for me would be a way to use an DoubleAnimationUsingPath and providing the X-Koordinate by external source.
But I am not sure if overall storyboards and animations are the best way to tackel that Problem.
If you know of any completely different Approach I am more than happy hear about it.
Kind regards
Just to get an idea of what can be done with animations, take a look at this little demo of a object moving along a track:
<Canvas>
<Canvas.Resources>
<PathGeometry x:Key="track">
<PathFigure StartPoint="200,100" IsClosed="True">
<LineSegment Point="300,100"/>
<ArcSegment SweepDirection="Clockwise"
Size="100,100" Point="300,300"/>
<LineSegment Point="200,300"/>
<ArcSegment SweepDirection="Clockwise"
Size="100,100" Point="200,100"/>
</PathFigure>
</PathGeometry>
</Canvas.Resources>
<Canvas.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard>
<MatrixAnimationUsingPath
Storyboard.TargetName="train"
Storyboard.TargetProperty="RenderTransform.Matrix"
PathGeometry="{StaticResource track}"
DoesRotateWithTangent="True"
Duration="0:0:10"
RepeatBehavior="Forever"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Canvas.Triggers>
<Path Data="{StaticResource track}" Stroke="Black"
StrokeThickness="6"/>
<Path Data="{StaticResource track}" Stroke="White"
StrokeThickness="4" StrokeDashArray="2,2"/>
<Rectangle x:Name="train" Width="10" Height="6" Fill="Red"
Canvas.Left="-5" Canvas.Top="-3"
RenderTransformOrigin="0.5,0.5">
<Rectangle.RenderTransform>
<MatrixTransform />
</Rectangle.RenderTransform>
</Rectangle>
</Canvas>

Rotate image inside a button UWP

I'm trying to rotate a font icon inside a button 90° in the first click and back to 0° on the second click.
Currently I have:
<Page.Resources>
<Storyboard x:Name="RotateButton90Degrees">
<DoubleAnimation
EnableDependentAnimation="True"
Storyboard.TargetName="ShowSubTasks_ButtonRotateTransform"
Storyboard.TargetProperty="Angle"
From="0"
To="90"
Duration="350" />
</Storyboard>
</Page.Resources>
<Button
x:Name="ShowSubTasks_Button"
Background="Transparent">
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="Click">
<media:ControlStoryboardAction Storyboard="{StaticResource RotateButton90Degrees}" />
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
<FontIcon
FontFamily="Segoe MDL2 Assets"
Glyph=""
RenderTransformOrigin="0.5, 0.5">
<FontIcon.RenderTransform>
<RotateTransform x:Name="ShowSubTasks_ButtonRotateTransform" />
</FontIcon.RenderTransform>
</FontIcon>
</Button>
The problem is that the app crashes when I click the button (it's not finding the ShowSubTasks_ButtonRotateTransform). The second is that I don't know how to revert the rotation effect after the first click (first click -> 90°, second click -> 0°, third click -> 90° and so on).
Any help would be appreciated.
Ok i got the problem, the thing is that im running all that code inside a DataTemplate ... So that explains why its crashing. For the fix i used what #Dishant suggested, created two storyboards and with a DataTriggerBehavior i change the angle of the rotate transform
<StackPanel.Resources>
<Storyboard x:Name="RotateButtonTo90Degrees">
<DoubleAnimation
EnableDependentAnimation="True"
Storyboard.TargetName="ShowSubTasks_ButtonRotateTransform"
Storyboard.TargetProperty="Angle"
From="0"
To="90"
Duration="0:0:0.1" />
</Storyboard>
<Storyboard x:Name="RotateButtonTo0Degrees">
<DoubleAnimation
EnableDependentAnimation="True"
Storyboard.TargetName="ShowSubTasks_ButtonRotateTransform"
Storyboard.TargetProperty="Angle"
From="90"
To="0"
Duration="0:0:0.1" />
</Storyboard>
</StackPanel.Resources>
<Button
Background="Transparent"
Visibility="{Binding HasSubTasks, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}">
<interactivity:Interaction.Behaviors>
<core:DataTriggerBehavior Binding="{Binding ShowSubTasks, Mode=OneWay}" Value="True">
<media:ControlStoryboardAction Storyboard="{StaticResource RotateButtonTo90Degrees}" />
</core:DataTriggerBehavior>
<core:DataTriggerBehavior Binding="{Binding ShowSubTasks, Mode=OneWay}" Value="False">
<media:ControlStoryboardAction Storyboard="{StaticResource RotateButtonTo0Degrees}" />
</core:DataTriggerBehavior>
</interactivity:Interaction.Behaviors>
<FontIcon
FontFamily="Segoe MDL2 Assets"
Glyph=""
RenderTransformOrigin="0.5, 0.5">
<FontIcon.RenderTransform>
<RotateTransform x:Name="ShowSubTasks_ButtonRotateTransform" />
</FontIcon.RenderTransform>
</FontIcon>
</Button>
Also as #MartinZikmund suggested, i needed to change the duration from 350 to something like 0:0:0.5
In my case the app does not crash, but the icon does not rotate, because the duration is set to 350, which basically means 350 hours. If you change this value to something like 0:0:0.5, it should rotate in 0.5 seconds. To do the reverse animation, you would probably need to set the animation target programatically, but in such case you could just run the storyboard itself in the Click event handler.
If you are targeting Windows 10 15063 or higher, you can use Implicit Animations in XAML. In that case you could set up an implicit animation on the rotation of the icon and then just set the rotation property in the code-behind accordingly and implicit animation would take care of the animation itself.

Is it Possible to animate path.Data

I have code something like this:
<Path x:Name="arrow" StrokeThickness="3" Stroke="Black" Data="M34,115 C45,106 91,119 105,112 119,105 172,75.004352 188,82.003591" />
what I want is to animate the Data property of the path. I'm searching this from last two days didn't find a solution.
what I actually want is to show path bit by bit.
Does anyone have any Idea?
"what I actually want is to show path bit by bit"
Do you mean something like this?
<Grid VerticalAlignment="Center" HorizontalAlignment="Center" >
<Grid.Resources>
<Storyboard x:Key="CWTrace">
<!-- To run opposite direction, just swap the 'From' and 'To' values. -->
<DoubleAnimation BeginTime="00:00:0.5" RepeatBehavior="Forever"
Storyboard.TargetName="arrow"
Storyboard.TargetProperty="StrokeDashOffset"
Duration="0:0:5" From="100" To="0"/>
</Storyboard>
</Grid.Resources>
<Grid.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard Storyboard="{StaticResource CWTrace}"/>
</EventTrigger>
</Grid.Triggers>
<Path x:Name="arrow"
StrokeDashOffset="0" StrokeDashArray="100"
StrokeThickness="3" Stroke="Black"
Data="M34,115 C45,106 91,119 105,112 119,105 172,75.004352 188,82.003591"/>
</Grid>
Obviously remove the RepeatBehavior for a one time anim, and tinker with values to get exactly what you're after. Cheers.

WPF rotating button

Help me plz. I need to animate rotation of the button on z-axis without using external libraries, only with C# and xaml code.
Is that possible? How can I do that?
Thanks.
Have a look at Viewport2DVisual3D
The example in the link does exactly that.
Edit: Here is the example from the link with an added animation of the Z axis
Looks like this
<Viewport3D>
<Viewport3D.Camera>
<PerspectiveCamera Position="0, 0, 4"/>
</Viewport3D.Camera>
<Viewport2DVisual3D x:Name="v2dv3d">
<Viewport2DVisual3D.Transform>
<RotateTransform3D>
<RotateTransform3D.Rotation>
<AxisAngleRotation3D Angle="0" Axis="0, 1, 0" />
</RotateTransform3D.Rotation>
</RotateTransform3D>
</Viewport2DVisual3D.Transform>
<Viewport2DVisual3D.Geometry>
<MeshGeometry3D Positions="-1,1,0 -1,-1,0 1,-1,0 1,1,0"
TextureCoordinates="0,0 0,1 1,1 1,0" TriangleIndices="0 1 2 0 2 3"/>
</Viewport2DVisual3D.Geometry>
<Viewport2DVisual3D.Material>
<DiffuseMaterial Viewport2DVisual3D.IsVisualHostMaterial="True" Brush="White"/>
</Viewport2DVisual3D.Material>
<Button Content="Hello, 3D">
<Button.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard>
<Storyboard RepeatBehavior="Forever">
<Rotation3DAnimation Storyboard.TargetName="v2dv3d"
Storyboard.TargetProperty="(Viewport2DVisual3D.Transform).(RotateTransform3D.Rotation)"
Duration="0:0:2"
BeginTime="0:0:0">
<Rotation3DAnimation.From>
<AxisAngleRotation3D Angle="0" Axis="0, 1, 0" />
</Rotation3DAnimation.From>
<Rotation3DAnimation.To>
<AxisAngleRotation3D Angle="90" Axis="0, 1, 0" />
</Rotation3DAnimation.To>
</Rotation3DAnimation>
<Rotation3DAnimation Storyboard.TargetName="v2dv3d"
Storyboard.TargetProperty="(Viewport2DVisual3D.Transform).(RotateTransform3D.Rotation)"
Duration="0:0:2"
BeginTime="0:0:2">
<Rotation3DAnimation.From>
<AxisAngleRotation3D Angle="-90" Axis="0, 1, 0" />
</Rotation3DAnimation.From>
<Rotation3DAnimation.To>
<AxisAngleRotation3D Angle="0" Axis="0, 1, 0" />
</Rotation3DAnimation.To>
</Rotation3DAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
</Viewport2DVisual3D>
<ModelVisual3D>
<ModelVisual3D.Content>
<DirectionalLight Color="#FFFFFFFF" Direction="0,0,-1"/>
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D>
Transformations may help you in this case. Look at here if that helps.
The RotateTransform class is used to rotate a WPF object in an X-Y
plane. It can be applied via XAML or directly via imperative code.
If you only need to rotate your button about the Z axis, then you won't need any 3D graphics. All UIElements (such as Buttons) have the property RenderTransform, which enables basic transformation of their default appearance. By means of Storyboards, WPF allows you to animate almost any dependency property. You can use a storyboard, triggered on load, to animate the Angle property of a RotateTransform applied to the button:
<Button Width="100" Height="100" Content="Wheeee!">
<Button.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard>
<Storyboard Storyboard.TargetName="ButtonRotation" Storyboard.TargetProperty="Angle">
<DoubleAnimation From="0" To="360" Duration="0:0:3" RepeatBehavior="Forever"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
<Button.RenderTransform>
<RotateTransform x:Name="ButtonRotation" CenterX="50" CenterY="50" Angle="45"/>
</Button.RenderTransform>
</Button>
The Viewport2DVisual3D, as recommended by #Meleak, also supports animation, and is fun to play with if you have time. To animate the MSDN example, you need to add a name to the AxisAngleRotation3D element and switch it to target the Z axis:
<AxisAngleRotation3D x:Name="RotateAboutZ" Angle="40" Axis="0, 0, 1" />
Then, as above, trigger a storyboard to begin on the Loaded event of the Viewport3D. In either case, if you need more control over the animation, you can make your storyboard a named resource to be referenced by other events, or even build and control it entirely in code.
More about 2D transforms
More about 3D transforms

Categories