ide*_*lix 0 wpf textbox dispatcher backgroundworker
我有日志拖尾应用程序,它在不定式循环中执行后台工作程序线程并检查某些TXT文件中的最新条目.一旦找到新条目,我使用Dispatcher.Invoke更新屏幕上的TextBox,并将最新条目添加到文本文件中.
问题是,如果源文本文件每毫秒不断更新,用户界面就会冻结,因为Dispatcher.Invoke经常更新文本框.
不知道是否有任何解决方法.我可以从文本文件中获取更大的块但不想破坏日志拖尾的实时体验,也不想延迟通过UI线程将行写入TextBox,因为这会使我的应用程序与实际数据不同步源文本文件.
这是后台工作者的DoWork方法
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;
}
}
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,UI线程只是简单地将文本附加到TextBox,并且当它经常发生接口冻结时
使用Dispatcher.Invoke是一个同步调用,因此它实际上与在UI线程上执行此操作相同,因为Invoke在UI执行所请求的任务之前调用阻塞.如果你在短时间内做得太多,那么你就有效地阻止了UI线程.
相反,您应该使用Dispatcher.BeginInvokeUI线程的工作队列,但不阻止.这将稍微好一些,就好像你在短时间内做得太多,你仍然充斥着UI线程的工作,这将花费大量时间来完成这项工作.
相反,最好的方法是将这些更改排队到UI线程,然后当队列达到定义的限制(即100个新的文本行)或超过特定的时间量(比如200ms)时,然后调用Dispatcher.BeginInvokesend对UI的这些更改.这将为您提供最佳的UI响应能力.
| 归档时间: |
|
| 查看次数: |
5556 次 |
| 最近记录: |