Поверните сетку, используя раскадровку вдоль кратчайшего "маршрута"

Я разрабатываю "компасоподобный" элемент управления, который может вращаться вдоль значения в диапазоне от 0 до 360 градусов; то есть полный круг. Устанавливая свойство в ViewModel, Grid анимируется под новым углом. Анимация, однако, не использует кратчайший путь к новому углу, когда он, например, поворачивается от 10 градусов до 350. Он вращается по часовой стрелке почти весь круг.

Но чего я хотел бы добиться, так это чтобы анимация проходила по кратчайшему маршруту: от 10 до 350 следует анимировать против часовой стрелки всего на 20 градусов.

Ниже я добавил составленный пример моего кода, но вместо привязки к свойству в ViewModel он использует привязку к ListBox (копирование-вставка должна запустить его). Выбор элемента в ListBox вращает сетку (которая содержит "иглу").

Если возможно, я бы предпочел решение "все XAML". Это вообще выполнимо, чего я пытаюсь достичь?

<Window x:Class="CompassRotation.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="375" Width="525">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="100" />
        </Grid.ColumnDefinitions>

        <Grid>
            <Ellipse Width="300" Height="300" Fill="DarkCyan" />
            <Label Content="{Binding SelectedItem.Content, ElementName=Angle, UpdateSourceTrigger=Explicit}"
                   FontSize="36" />
            <Grid Width="300" Height="300"
                  RenderTransformOrigin="0.5,0.5"
                  Tag="{Binding SelectedItem.Content, ElementName=Angle, UpdateSourceTrigger=PropertyChanged,NotifyOnTargetUpdated=True}">
                <Grid.Triggers>
                    <EventTrigger RoutedEvent="Binding.TargetUpdated">
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation
                                    Storyboard.TargetProperty="(Grid.RenderTransform).(RotateTransform.Angle)"
                                    Duration="0:0:1" />
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger>
                </Grid.Triggers>

                <Grid.RenderTransform>
                    <RotateTransform Angle="{Binding SelectedItem.Content, ElementName=Angle, FallbackValue=45}" />
                </Grid.RenderTransform>

                <Rectangle Width="15" Height="300">
                    <Rectangle.Fill>
                        <LinearGradientBrush>
                            <GradientStopCollection>
                                <GradientStop Color="Red" Offset="0" />
                                <GradientStop Color="Green" Offset="1" />
                            </GradientStopCollection>
                        </LinearGradientBrush>
                    </Rectangle.Fill>
                </Rectangle>
            </Grid>
        </Grid>
        <ListBox Grid.Column="1" Name="Angle">
            <ListBoxItem>0</ListBoxItem>
            <ListBoxItem>45</ListBoxItem>
            <ListBoxItem>90</ListBoxItem>
            <ListBoxItem>135</ListBoxItem>
            <ListBoxItem>180</ListBoxItem>
            <ListBoxItem>225</ListBoxItem>
            <ListBoxItem>270</ListBoxItem>
            <ListBoxItem>305</ListBoxItem>
            <ListBoxItem>360</ListBoxItem>
        </ListBox>
    </Grid>
</Window>

1 ответ

Решение

DoubleAnimation имеет From свойство, с которым вы можете связать, чтобы установить начальное значение анимации.

Поэтому перед обновлением ViewModel Angle значение от 10 до 350 против часовой стрелки, установите ViewModel's From значение до 370, и анимация будет прокручиваться против часовой стрелки от отметки 370 (=10) градусов до 350.

Это оставляет вопрос о том, как определить From значение, чтобы установить, если вы собираетесь обновить Angle от стоимости from в to,

Мы знаем одно: From свойство для установки должно быть в интервале [to - 180, to + 180], чтобы убедиться, что поворот идет по кратчайшему пути к to,

Если мы называем нижнюю границу этого интервала lowerbound = to - 180, затем

From = lowerbound + (from - lowerbound) % 360

Или на самом деле, так как % ведет себя странно для отрицательных значений, более безопасная формула, которая работает для from а также to углы в диапазоне [-360,360] является

From = lowerbound + (from - lowerbound + 720) % 360
Другие вопросы по тегам