我编写了这个示例,它通过计时器在代码后面的椭圆周围设置路径动画。问题是,路径元素随着路径的变化而稍微摆动。除了轻微的摇晃外,行为似乎基本正常。有什么想法我该怎么纠正吗?
顺便说一句,右边的ListBox只是用来显示计算出的点,以确保它们是我所期望的。
<Window x:Class="AnimationSamples.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" WindowStartupLocation="CenterScreen">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Degree}" HorizontalAlignment="Right" Margin="9"></TextBlock>
<Grid>
<Border BorderBrush="SteelBlue" BorderThickness="0">
<Grid Width="200" Height="200" HorizontalAlignment="Center" VerticalAlignment="Center">
<Ellipse Fill="SteelBlue"></Ellipse>
<Path x:Name="_pathTest" Data="M 0,90 A 90,90 0 1 1 90,180" StrokeThickness="4" Stroke="LightSkyBlue"
Visibility="Visible" HorizontalAlignment="Center" VerticalAlignment="Center"
Margin="2,2,0,0"/>
<Path x:Name="_pathTarget" Stretch="None"
Data="{Binding PathData}" Fill="Transparent" StrokeThickness="10"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Stroke="White">
<Path.RenderTransform>
<TranslateTransform X="10" Y="10"/>
</Path.RenderTransform>
</Path>
</Grid>
</Border>
</Grid>
<ListBox x:Name="_lbDoubleCheckPoints"
Grid.Column="1" ItemsSource="{Binding Points}"
BorderBrush="Transparent" Background="Transparent"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<Canvas HorizontalAlignment="Center" VerticalAlignment="Center">
</Canvas>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Ellipse Width="1" Height="1" Fill="Red"/>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Focusable" Value="False"></Setter>
<Setter Property="Canvas.Left" Value="{Binding X}"/>
<Setter Property="Canvas.Top" Value="{Binding Y}"/>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</Grid>
下面是代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Timers;
namespace AnimationSamples
{
public partial class MainWindow : Window
{
public MainWindow()
{
this.DataContext = new ViewModel();
InitializeComponent();
}
public class ViewModel : NotifyRoot
{
Geometry _pathData = null;
public Geometry PathData
{
get { return _pathData; }
set { _pathData = value; RaiseChanged("PathData"); }
}
double _dDegree = 180.0;
public double Degree
{
get { return _dDegree; }
set { if (_dDegree != value) { _dDegree = value; RaiseChanged("Degree"); } }
}
public IEnumerable<Point> Points { get; set; }
///////////////////////////////////////////////////////////////////
Timer _timer = new Timer(1) { AutoReset = true };
Point[] _pts = new Point[360];
Point _ptStart;
///////////////////////////////////////////////////////////////////
public ViewModel()
{
// calculate points around circle
double r = 90;
for (int i = 0; i < 360; i++)
{
double rad = Helper.ToRadians(i);
_pts[i] = new Point(r * Math.Sin(rad), r * Math.Cos(rad));
}
_ptStart = _pts[180];
Points = _pts.AsEnumerable();
_timer.Elapsed += (object sender, ElapsedEventArgs e) =>
{
Degree = (Degree + 1) % 360;
int iArc = (Degree < 179) ? 1 : 0;
Point pt = _pts[(int)Degree];
// M 0,90 A 90,90, 30 1 0 90, 0
PathData = Geometry.Parse(
string.Format(
"M {0},{1} A {2},{2}, 0 {3} 0 {4},{5}",
r + Math.Round(_ptStart.X), r + Math.Round(_ptStart.Y),
r, iArc,
r + Math.Round(pt.X), r + Math.Round(pt.Y)));
Debug.Assert(PathData != null);
};
_timer.Start();
}
}
}
public class Helper
{
public static double ToRadians(double d)
{
return d * Math.PI / 180;
}
}
public class NotifyRoot : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void RaiseChanged(string strPropName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(strPropName));
}
}
}
}
非常感谢您的帮助。
====================================
感谢马克早些时候的回复。我对此做了更多的修改。这里有一个基本相同的XAML版本,没有代码隐藏。
<Grid>
<Border BorderBrush="SteelBlue" BorderThickness="0" Width="200" Height="200"
HorizontalAlignment="Center" VerticalAlignment="Center">
<Grid>
<Ellipse Fill="SteelBlue"/>
<Path x:Name="_pathTest2" Stretch="None"
Fill="Transparent" StrokeThickness="10"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Stroke="White">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigureCollection>
<PathFigure StartPoint="0,90">
<PathFigure.Segments>
<PathSegmentCollection>
<ArcSegment x:Name="_arc" RotationAngle="0" Size="90,90" IsLargeArc="True"
Point="0,90.001" SweepDirection="Clockwise"/>
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
</PathFigureCollection>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
<Path.Triggers>
<EventTrigger RoutedEvent="Path.Loaded">
<BeginStoryboard x:Name="_sb0">
<Storyboard TargetName="_arc" AutoReverse="False"
DecelerationRatio="0.99"
RepeatBehavior="Forever" SpeedRatio="1.2">
<PointAnimationUsingPath Storyboard.TargetProperty="Point" Duration="0:0:1.5" >
<PointAnimationUsingPath.PathGeometry>
<PathGeometry Figures="M 0,90 A 90,90 0 1 1 0,90.001" />
</PointAnimationUsingPath.PathGeometry>
</PointAnimationUsingPath>
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="IsLargeArc" Duration="0:0:1.5">
<DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="False" />
<DiscreteBooleanKeyFrame KeyTime="0:0:0.75" Value="True" />
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Path.Triggers>
<Path.RenderTransform>
<TranslateTransform X="10" Y="10"/>
</Path.RenderTransform>
</Path>
</Grid>
</Border>
</Grid>
去掉路径生成代码中的Math.Round():
// M 0,90 A 90,90, 30 1 0 90, 0
PathData = Geometry.Parse(
string.Format(
"M {0},{1} A {2},{2}, 0 {3} 0 {4},{5}",
r + _ptStart.X, r + _ptStart.Y,
r, iArc,
r + pt.X, r + pt.Y));