我正试图创造一种雷达。雷达是VisualCollection,由360个DrawingVisual(代表雷达波束)组成。雷达放在Viewbox上。
class Radar : FrameworkElement
{
private VisualCollection visuals;
private Beam[] beams = new Beam[BEAM_POSITIONS_AMOUNT]; // all geometry calculation goes here
public Radar()
{
visuals = new VisualCollection(this);
for (int beamIndex = 0; beamIndex < BEAM_POSITIONS_AMOUNT; beamIndex++)
{
DrawingVisual dv = new DrawingVisual();
visuals.Add(dv);
using (DrawingContext dc = dv.RenderOpen())
{
dc.DrawGeometry(Brushes.Black, null, beams[beamIndex].Geometry);
}
}
DrawingVisual line = new DrawingVisual();
visuals.Add(line);
// DISCRETES_AMOUNT is about 500
this.Width = DISCRETES_AMOUNT * 2;
this.Height = DISCRETES_AMOUNT * 2;
}
public void Draw(int beamIndex, Brush brush)
{
using (DrawingContext dc = ((DrawingVisual)visuals[beamIndex]).RenderOpen())
{
dc.DrawGeometry(brush, null, beams[beamIndex].Geometry);
}
}
protected override Visual GetVisualChild(int index)
{
return visuals[index];
}
protected override int VisualChildrenCount
{
get { return visuals.Count; }
}
}
每个DrawingVisual都有DrawingContext.DrawGeometry(画笔,笔,几何)的预先计算的几何体。 Pen为null,brush为LinearGradientBrush,大约有500个GradientStop。刷子每隔几毫秒就会更新一次,例如16 ms就可以了。而那就是变得迟钝的东西。这就是整体逻辑。
在MainWindow()构造函数中,我创建雷达并启动后台线程:
private Radar radar;
public MainWindow()
{
InitializeComponent();
radar = new Radar();
viewbox.Child = radar;
Thread t = new Thread(new ThreadStart(Run));
t.Start();
}
在Run()方法中有一个无限循环,其中生成随机画笔,调用Dispatcher.Invoke()并设置16 ms的延迟:
private int beamIndex = 0;
private Random r = new Random();
private const int turnsPerMinute = 20;
private static long delay = 60 / turnsPerMinute * 1000 / (360 / 2);
private long deltaDelay = delay;
public void Run()
{
int beginTime = Environment.TickCount;
while (true)
{
GradientStopCollection gsc = new GradientStopCollection(DISCRETES_AMOUNT);
for (int i = 1; i < Settings.DISCRETES_AMOUNT + 1; i++)
{
byte color = (byte)r.Next(255);
gsc.Add(new GradientStop(Color.FromArgb(255, 0, color, 0), (double)i / (double)DISCRETES_AMOUNT));
}
LinearGradientBrush lgb = new LinearGradientBrush(gsc);
lgb.StartPoint = Beam.GradientStarts[beamIndex];
lgb.EndPoint = Beam.GradientStops[beamIndex];
lgb.Freeze();
viewbox.Dispatcher.Invoke(new Action( () =>
{
radar.Draw(beamIndex, lgb);
}));
beamIndex++;
if (beamIndex >= BEAM_POSITIONS_AMOUNT)
{
beamIndex = 0;
}
while (Environment.TickCount - beginTime < delay) { }
delay += deltaDelay;
}
}
每次Invoke()调用它都会执行一个简单的操作:dc.DrawGeometry(),它在当前beamIndex下重绘光束。但是,有时似乎在UI更新之前,雷达.Draw()被调用几次,而不是每16毫秒绘制1个波束,它每32-64毫秒绘制2-4个波束。这令人不安。我真的想要实现平稳运动。我需要一个光束在每个确切的时间段内绘制。不是这个随机的东西。这是我到目前为止所尝试的清单(没有任何帮助):
我没有尝试:
所以,就是这样。我求救。
编辑:这些滞后与PC资源无关 - 没有延迟,雷达每秒可以做大约5个完整的圆圈(移动非常快)。很可能是关于多线程/ UI / Dispatcher或其他我尚未理解的东西。
EDIT2:附加.exe文件,以便您可以看到实际发生的情况:https://dl.dropboxusercontent.com/u/8761356/Radar.exe
EDIT3: DispatcherTimer(DispatcherPriority.Render)也没有帮助。
答案 0 :(得分:3)
对于流畅的WPF动画,你应该使用
CompositionTarget.Rendering
事件。
不需要线程或搞乱调度员。该事件将在每个新帧之前自动触发,类似于HTML的requestAnimationFrame()
。
在更新你的WPF场景的事件中,你已经完成了!
MSDN上有complete example。
答案 1 :(得分:0)
您可以使用WPF Performance Suite检查一些图形瓶颈:
http://msdn.microsoft.com/es-es/library/aa969767(v=vs.110).aspx
Perforator是向您展示性能问题的工具。也许您使用的是低性能VGA卡?
答案 2 :(得分:0)
while (Environment.TickCount - beginTime < delay) { }
delay += deltaDelay;
上面的序列会阻塞线程。改为使用&#34;等待Task.Delay(...)&#34;它没有像对应的Thread.Sleep(...)那样阻塞线程。