我在尝试制造一种雷达。雷达是VisualCollection,它由360个DrawingVisual(代表雷达波束)组成。雷达被放置在视箱上。
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(画笔、笔、几何图形)的几何形状。钢笔为空,而画笔为LinearGradientBrush,约为500 GradientStops。这个刷子每隔几毫秒更新一次,比方说这个例子是16毫秒。这就是导致滞后的原因。这是总的逻辑。
在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更新之前一样,radar.Draw()被调用了几次,它不是每16毫秒绘制一个光束,而是每32-64毫秒绘制2-4个横梁。这是令人不安的。我真的很想实现流畅的运动。我需要一根横梁来按精确的时间绘制。不是这些随机的东西。这是我迄今尝试过的(没有任何帮助)的清单:
我没有尝试的是:
所以,就是这样。我在乞求帮助。
编辑:这些延迟与PC资源无关--雷达每秒可以完成5圈左右(移动速度相当快)。很可能是关于多线程/UI/Dispatcher或者其他一些我还没有理解的东西。
EDIT2:附加了一个.exe文件,这样您就可以看到实际发生了什么:https://dl.dropboxusercontent.com/u/8761356/Radar.exe
EDIT3: DispatcherTimer(DispatcherPriority.Render)也没有帮上忙。
发布于 2014-05-28 07:50:00
对于流畅的WPF动画,您应该使用CompositionTarget.Rendering事件。
不需要线程或干扰调度程序。该事件将在每一个新框架之前自动触发,类似于HTML的requestAnimationFrame()。
在事件中,更新您的WPF场景,您就完成了!
在MSDN上有一个可用的完整示例。
发布于 2014-05-27 12:25:36
您可以使用WPF性能套件检查一些图形瓶颈:
http://msdn.microsoft.com/es-es/library/aa969767(v=vs.110).aspx
射孔器是向您展示性能问题的工具。也许你用的是低性能的VGA卡?
发布于 2014-05-28 06:49:37
while (Environment.TickCount - beginTime < delay) { }
delay += deltaDelay;上面的顺序阻塞了线程。使用“等待Task.Delay(.)”它不像其对应的Thread.Sleep(.)那样阻塞线程。
https://stackoverflow.com/questions/23889294
复制相似问题