Вот сделал класс анимации:
public class VisualRenderer : FrameworkElement
{
private static readonly DependencyPropertyKey MarkerPositionPropertyKey = DependencyProperty.RegisterReadOnly("MarkerPosition", typeof(Point), typeof(VisualRenderer), new FrameworkPropertyMetadata(new Point(100, 100), FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender));
private static readonly DependencyProperty MarkerPositionProperty = MarkerPositionPropertyKey.DependencyProperty;
public Point MarkerPosition
{
get => (Point)GetValue(MarkerPositionProperty);
set
{
if (Interlocked.Read(ref LockRender) == 0)
{
Dispatcher.Invoke(new Action(() => SetValue(MarkerPositionPropertyKey, value)));
}
}
}
private static readonly DependencyPropertyKey InfoPropertyKey = DependencyProperty.RegisterReadOnly("Info", typeof(string), typeof(VisualRenderer), new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender));
private static readonly DependencyProperty InfoProperty = InfoPropertyKey.DependencyProperty;
public string Info
{
get => (string)GetValue(InfoProperty);
set
{
if (Interlocked.Read(ref LockRender) == 0)
{
Dispatcher.Invoke(new Action(() => SetValue(InfoPropertyKey, value)));
}
}
}
private static readonly DependencyPropertyKey MarkerSizePropertyKey = DependencyProperty.RegisterReadOnly("MarkerSize", typeof(int), typeof(VisualRenderer), new FrameworkPropertyMetadata(25, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender));
private static readonly DependencyProperty MarkerSizeProperty = MarkerSizePropertyKey.DependencyProperty;
public int MarkerSize
{
get => (int)GetValue(MarkerSizeProperty);
set => SetValue(MarkerSizePropertyKey, value);
}
SolidColorBrush borderBrush;
SolidColorBrush markerBrush = Brushes.Red;
SolidColorBrush marker2Brush = Brushes.Blue;
Pen borderPen;
public delegate void OnPreviewChanged();
public event OnPreviewChanged onPreviewChangedEvent;
/// <summary>
/// Получает границы рабочей области с учетом размера метки
/// </summary>
public Rect MarkerBorders
{
get
{
return new Rect()
{
X = 0,
Y = 0,
Width = ActualWidth,
Height = ActualHeight
};
}
}
public VisualRenderer()
{
ResetDefaultsParam();
}
/// <summary>
/// Устанавливает параметры по умолчнию
/// </summary>
public void ResetDefaultsParam()
{
borderBrush = new SolidColorBrush(Color.FromArgb(0xFF, 0xA1, 0xD2, 0x5A));
borderPen = new Pen(borderBrush, 5);
MarkerPosition = new Point(RenderSize.Width / 2, RenderSize.Height / 2);
}
long LockRender = 0;
protected override void OnRender(DrawingContext drawingContext)
{
if (Interlocked.CompareExchange(ref LockRender, 1, 0) == 0)
{
drawingContext.PushClip(new RectangleGeometry(new Rect(RenderSize)));
drawingContext.DrawRectangle(null, new Pen(borderBrush, 8), new Rect(0, 0, RenderSize.Width, RenderSize.Height));
drawingContext.DrawRectangle(null, borderPen, new Rect(RenderSize.Width / 2, 0, RenderSize.Width / 2, RenderSize.Height));
drawingContext.DrawRectangle(null, borderPen, new Rect(0, RenderSize.Height / 2, RenderSize.Width, RenderSize.Height / 2));
drawingContext.DrawEllipse(markerBrush, new Pen(Brushes.Black, 1), MarkerPosition, MarkerSize, MarkerSize);
FormattedText formattedText = new FormattedText(Info, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, new Typeface("Verdana"), 16, Brushes.Black, VisualTreeHelper.GetDpi(this).PixelsPerDip);
drawingContext.DrawText(formattedText, new Point(RenderSize.Width / 2, 50));
drawingContext.Pop();
onPreviewChangedEvent?.Invoke();
Interlocked.Exchange(ref LockRender, 0);
}
base.OnRender(drawingContext);
}
protected override Size MeasureOverride(Size availableSize)
{
return base.MeasureOverride(availableSize);
}
}
Вот поток который выполняет обновление положения метки по синусоиды с разным значением частоты:
if (thread == null)
{
angle = 0;
double Hz = 1.0;
double[] Hzs = new double[] { 0.1, 0.2, 0.3, 0.4, 0.5 };
int[] secTimes = new int[] { 10, 10, 5, 5, 5 };
int[] defAngle = new int[] { 0, 0, 0, 180, 180 };
int testCnt = 0;
R = GetMaxBorder();
// initializition
Hz = Hzs[testCnt];
cancel = false;
System.Diagnostics.Stopwatch stw = new System.Diagnostics.Stopwatch();
TimeSpan lasttime = stw.Elapsed;
thread = new Thread(new ThreadStart(() =>
{
stw.Restart();
lasttime = stw.Elapsed;
while (!cancel)
{
var delta = stw.Elapsed - lasttime;
lasttime = stw.Elapsed;
double step = (360.0 * Hz) * (double)delta.TotalSeconds;
if (stw.Elapsed.TotalSeconds >= secTimes[testCnt])
{
if (testCnt < Hzs.Length - 1)
{
testCnt++;
Hz = Hzs[testCnt];
stw.Restart();
lasttime = stw.Elapsed;
angle = defAngle[testCnt];
step = 0;
}
else
{
stw.Stop();
lasttime = stw.Elapsed;
cancel = true;
}
}
angle += step;
string info = "Test: " + Hzs[testCnt].ToString() + " Hz, " + secTimes[testCnt] + " sec., TotalTime: " + stw.Elapsed.Seconds.ToString() + " sec.";
SetMarkerPos(new Point(angle, 0), info);
Thread.Sleep(5);
}
SetMarkerPos(new Point(), "Complete");
}));
thread.Start();
}
else
{
cancel = true;
thread = null;
}
Но все равно вроде бы как при приближении метки к центру наблюдаются какие то рывки. Нету плавности движения.
Почему?? что тут еще то можно сделать итак ведь частота обновления метки почти 200 герц.
WpfApp1.7z (7.6 КБ)