Dispatcher.Invoke循环冻结UI [英] Dispatcher.Invoke loop freeze UI

查看:296
本文介绍了Dispatcher.Invoke循环冻结UI的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有日志跟踪应用程序,该应用程序在无限循环中执行后台工作线程,并检查某些TXT文件中的最新条目.找到新条目后,我将使用Dispatcher.Invoke更新屏幕上的TextBox,并将最新条目添加到文本文件中.

I have log tailing app which is executing Background worker thread in infinitive loop and checking for latest entries inside some TXT file. Once it find new entries I use Dispatcher.Invoke to update TextBox on the screen with latest entry added to the text file.

问题在于,如果源文本文件每毫秒持续更新一次,由于Dispatcher.Invoke如此频繁地更新Textbox,则用户界面将被冻结.

The problem is that if the source text file is being updated constantly every millisecond the user interface is just freezing since Dispatcher.Invoke is updating Textbox so often.

想知道是否有任何解决方法.我可以从文本文件中获取更大的块,但不想破坏日志尾随的实时体验,也不想延迟通过UI线程将行写入TextBox的过程,因为这会使我的应用程序与内部的实际数据不同步源文本文件.

Wonder if there is any workaround. I could get bigger chunks from text file but don't want to spoil log tailing real-time experience, also don't want to delay writing of lines to TextBox by UI thread as this will get my application out of sync with actual data inside source text file.

这是后台工作程序DoWork方法

Here is the Background worker DoWork method

private void worker_DoWork(object sender, DoWorkEventArgs e)
{
  reader = new StreamReader(new FileStream(file.File, FileMode.Open, FileAccess.Read, FileShare.ReadWrite));
  lastMaxOffset = reader.BaseStream.Length;

  while (true)
  {
    if (worker.CancellationPending)
    {
      e.Cancel = true;
      break;
    }                

    if (reader.BaseStream.Length == lastMaxOffset)
      continue;

    reader.BaseStream.Seek(lastMaxOffset, SeekOrigin.Begin);

    string line = "";
    while ((line = reader.ReadLine()) != null)

    this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, (Action)(() =>
    {
      textLog.Text += "\r" + line;
      scrollViewer.ScrollToBottom();
    })); 

    lastMaxOffset = reader.BaseStream.Position;        
  }
}

如您所见,UI线程只是将文本追加到TextBox中,并且当它碰巧经常冻结界面时

as you can see UI thread is just simply append text to the TextBox and when it happen to often interface freeze

推荐答案

使用Dispatcher.Invoke是同步调用,因此它实际上与在UI线程上执行此操作相同,因为对Invoke的调用会阻塞直到UI执行请求的任务.如果您在短时间内执行过多操作,则实际上是在阻塞UI线程.

Using Dispatcher.Invoke is a synchronous call, so it is effectively the same as doing this on the UI thread, because the call to Invoke blocks until the UI performs the requested task. If you're doing that too much in a short time span you're effectively blocking the UI thread.

相反,您应该使用Dispatcher.BeginInvoke,它将UI线程的工作排入队列,但不会阻塞.这样会稍微好一点,就像您在短时间内做太多一样,您仍然在用大量的工作来填充UI线程来做,这将花费大量的时间来做这项工作.

Instead, you should use Dispatcher.BeginInvoke which queues up the work for the UI thread to do, but doesn't block. This will be marginally better, as if you're doing this too much in a short period of time, you're still flooding the UI thread with work to do an it's going to spend a lot of time doing that work.

相反,最好的方法是将对UI线程所做的更改排队,然后当队列达到定义的限制(即100行新文本)或超过特定时间(例如200ms)时,调用Dispatcher.BeginInvoke将这些更改发送到UI.这将为您提供最佳的UI响应速度.

Instead, what best approach would be is queue up those changes to the UI thread, and then when the queue reaches a defined limit (ie. 100 new lines of text) or exceeds a specific amount of time (say 200ms) then call Dispatcher.BeginInvoke to send those changes to the UI. This will give you the best UI responsiveness.

这篇关于Dispatcher.Invoke循环冻结UI的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆