Dispatcher.Invoke更新WPF画布会导致性能问题

时间:2017-08-26 19:37:43

标签: c# wpf multithreading canvas websocket

我正在使用Websockets在画布上绘制数据:

webSocket.OnMessage += (sender, e) =>
{
    String websocketData = e.Data.Substring(3);
    WebSocketDataStructure jsonData = JsonConvert.DeserializeObject<WebSocketDataStructure>(websocketData);

    // Give control back to main thread for drawing
    Application.Current.Dispatcher.BeginInvoke(
      DispatcherPriority.Background,
      new Action(() => this.updateCanvas(jsonData)));
    };

private void updateCanvas(WebSocketDataStructure myData)
{
    CanvasUtils.DrawLine(MyCanvas, colorNormalBrush, myData.hsLine.x1, myData.hsLine.y1, myData.hsLine.x2, myData.hsLine.y2);
}

当我每秒收到多条消息时,应用程序开始滞后。我读到使用Dispatcher.BeginInvoke()不适合处理频繁的数据,因为我们每次都会立即切换回UI-Thread。

有没有更好的方法来实现这个?我想过创建一个计时器并每隔一秒更新一次UI-Thread。这可以通过将websocket数据存储在List中,并在UI-Thread(https://en.wikipedia.org/wiki/Producer%E2%80%93consumer_problem)上处理它来实现。我唯一的问题是,我无法在UI-Thread上使用Thread.Sleep(1000)建立无限循环。

1 个答案:

答案 0 :(得分:1)

您可以将较高频率的数据排队,并以较低的速度从数据队列中读取项目。通过使用DispatcherTimer,您可以避免直接调用Dispatcher。

var queue = new ConcurrentQueue<WebSocketDataStructure>();

webSocket.OnMessage += (s, e) =>
{
    var websocketData = e.Data.Substring(3);
    var jsonData = JsonConvert.DeserializeObject<WebSocketDataStructure>(websocketData);

    queue.Enqueue(jsonData);
};

var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1) };

timer.Tick += (s, e) =>
{
    WebSocketDataStructure data;

    while (queue.TryDequeue(out data))
    {
        CanvasUtils.DrawLine(MyCanvas, colorNormalBrush,
            data.hsLine.x1, data.hsLine.y1, data.hsLine.x2, data.hsLine.y2);
    }
};

timer.Start();