gpt4 book ai didi

wpf - 如何实现每 16 毫秒流畅的 UI 更新?

转载 作者:行者123 更新时间:2023-12-04 12:41:09 25 4
gpt4 key购买 nike

我正在尝试创建一种雷达。 Radar 是由 360 DrawingVisual(代表雷达波束)组成的 VisualCollection。雷达放置在 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 为空,画笔是具有大约 500 个 GradientStops 的 LinearGradientBrush。画笔每隔几毫秒更新一次,在这个例子中假设是 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 毫秒绘制 1 个波束,而是每 32-64 毫秒绘制 2-4 个波束。这令人不安。我真的很想实现流畅的运动。我需要一个光束来绘制每个确切的时间段。不是这种随机的东西。这是我到目前为止尝试过的列表(没有任何帮助):
  • 将雷达放置在 Canvas 中;
  • 使用 Task、BackgroundWorker、Timer、自定义 Microtimer.dll 并设置不同的线程优先级;
  • 使用不同的延迟实现方式:Environment.TickCount、DateTime.Now.Ticks、Stopwatch.ElapsedMilliseconds;
  • 将 LinearGradientBrush 更改为预定义的 SolidColorBrush;
  • 使用 BeginInvoke() 而不是 Invoke() 并更改调度程序优先级;
  • 使用 InvalidateVisuals() 和丑陋的 DoEvents();
  • 使用 BitmapCache、WriteableBitmap 和 RenderTargetBitmap(使用 DrawingContext.DrawImage(bitmap);
  • 使用 360 Polygon 对象而不是 360 DrawingVisuals。这样我可以避免使用 Invoke() 方法。每个多边形的 Polygon.FillProperty 都绑定(bind)到 ObservableCollection,并实现了 INotifyPropertyChanged。如此简单的代码行 {brushCollection[beamIndex] = (new created and freeze brush)} 导致多边形 FillProperty 更新并且 UI 被重绘。但还是没有流畅的 Action ;
  • 可能还有一些我可以忘记的小解决方法。

  • 我没有尝试的:
  • 使用工具绘制3D(视口(viewport))绘制2D雷达;
  • ...

  • 所以,就是这样。我在乞求帮助。

    编辑:这些滞后与 PC 资源无关 - 没有延迟,雷达每秒可以完成大约 5 个完整的循环(移动速度非常快)。很可能是关于多线程/UI/Dispatcher 或其他我还没有理解的东西。

    EDIT2:附加一个 .exe 文件,以便您查看实际情况: https://dl.dropboxusercontent.com/u/8761356/Radar.exe

    EDIT3: DispatcherTimer(DispatcherPriority.Render) 也没有帮助。

    最佳答案

    对于流畅的 WPF 动画,您应该使用
    CompositionTarget.Rendering 事件。

    无需线程或与调度程序混淆。该事件将在每个新帧之前自动触发,类似于 HTML 的 requestAnimationFrame() .

    如果更新您的 WPF 场景,您就完成了!

    有一个complete example可在 MSDN 上找到。

    关于wpf - 如何实现每 16 毫秒流畅的 UI 更新?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23889294/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com