Поверните сетку, используя раскадровку вдоль кратчайшего "маршрута"
Я разрабатываю "компасоподобный" элемент управления, который может вращаться вдоль значения в диапазоне от 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