Search code examples
wpfvb.netxamlrotatetransform

Rotate element in steps of 45 degrees, always forward


Let's say I want to animate rotate an UI element 45 degrees clockwise each time I press a button.

I have defined 8 visual states setting different RotateTransform values between them. So, whenever I press the button I move to the next visual state:

VisualStateManager.GoToElementState(MyElement, "Position2", True)

etc.

The problem is that when moving from the VisualState 8 to VisualState 1, the element rotates backward. Seems logical, since it is moving from 315º to 0º.

The question is, how could achieve to goal of always moving forward when pressing the button?


Solution

  • I wrote a simple example for you in C#; VB should be very similar.

    In your Main Window put a Rectangle and a Button. Then, set the RenderTransformOrigin for the Rectangle like in the Xaml sample.

    In your code behind, declare your RotateTransform and attach it to the Rectangle as shown below. Everytime the Button is pressed, the Angle property of the RotateTransform is increased of 45.

    @EDIT: I like @Clemens formula to increase angle (it avoid overflows). I edited my answer.

    XAML:

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Rectangle x:Name="myRect" RenderTransformOrigin=".5,.5" Grid.Row="0" Width="100" Height="100" Fill="LightBlue" >
    
        </Rectangle>
        <Button Grid.Row="1" Width="100" Height="50" Margin="10" Click="Button_Click">Rotate</Button>
    </Grid>
    

    Window Code-Behind:

    public partial class MainWindow : Window
    {
        private TransformGroup _transformGroup;
        private RotateTransform _rotateTrsf;
    
        public MainWindow()
        {
            InitializeComponent();
            _transformGroup = new TransformGroup();
            _rotateTrsf = new RotateTransform();
            _transformGroup.Children.Add(_rotateTrsf);
    
            SetupAnimation();
    
            myRect.RenderTransform = _transformGroup;
        }
    
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            _rotateAnimation.To = Math.Floor(_rotateTrsf.Angle / 45 + 1) * 45;            
            _rotateTrsf.BeginAnimation(RotateTransform.AngleProperty, _rotateAnimation);
            _rotateAnimation.From = _rotateAnimation.To;            
        }
    
        private void SetupAnimation()
        {           
            _rotateAnimation = new DoubleAnimation();
            _rotateAnimation.From = 0.0;
            _rotateAnimation.To = 45;
            _rotateAnimation.Duration = new Duration(TimeSpan.FromSeconds(0.3));
        }
    }