[英]BackgroundWorker freezes my UI and BeginInvoke seems to go turtle speed
我必須做一個看似很簡單的任務:1)列出目錄(及其子目錄)中的所有文件,2)在多行文本框中顯示所有文件,然后3)在每個文件中執行一些操作。 由於2個問題,我被困在2)中,這是我的問題:
Form1.cs
是我管理UI並啟動運行Logic.cs
主要功能的BackgroundWorker
的Logic.cs
DependencyMapper.cs
是...好,我在其中處理文件夾/文件(在Fetch()
)並調用Form1
方法,該方法使用BeginInvoke
將每一行(當前文件的名稱)填充到Form1's
文本框中。 少說話,多代碼。 這是我的代碼的皮包骨頭,可以正常使用的版本:
Form1.cs
public partial class Form1 : Form
{
public DependencyMapper dep;
BackgroundWorker bwDep;
public Form1()
{
// I read here in SO to try put the BW stuff here don't know why, but hasn't helped.
InitializeComponent();
bwDep = new BackgroundWorker();
bwDep.DoWork += bwDep_DoWork;
bwDep.RunWorkerCompleted += bwDep_RunWorkerCompleted;
}
private void button1_Click(object sender, EventArgs e)
{
bwDep.RunWorkerAsync();
}
void bwDep_DoWork(object sender, DoWorkEventArgs e)
{
dep.Fetch(extensions);
}
public void SendBack(string msg) // To receive Fetch()s progress
{
textBox2.BeginInvoke(new Action(() =>
{
textBox2.Text += msg + "\r\n";
textBox2.SelectionStart = textBox2.Text.Length;
textBox2.ScrollToCaret();
}));
}
}
DependencyMapper.cs
public class DependencyMapper
{
private Form1 form;
public DependencyMapper(Form1 form1)
{
this.form = form1;
}
public void Fetch()
{
DirectoryInfo folder = new DirectoryInfo(form.Texto1);
FileInfo[] files = folder.GetFiles("*.*", SearchOption.AllDirectories);
for (int i = 0; i < files.Length; i++)
{
form.SendBack(files[i].FullName); // Kind of talking back to the UI through form's reference and SendBack method which uses BeginInvoke.
}
}
}
那么,我的應用程序正常工作嗎? 是的,但是我無法解決兩個巨大的問題:
BackgroundWorker
嗎?)。 並非完全如此,因為文本框是一個一個地添加每個文件,但是就像應該的那樣,但是我無法在窗口中四處移動或單擊任何按鈕。 PS:在使用BackgroundWorker
之前,我使用的是Thread
:UI完全沒有凍結,但是文本框的填充速度很慢。 這就是為什么我決定與BackgroundWorker
一起冒險,這只會帶來問題#1。
謝謝。
您消防沖水 UI線程,產生的結果遠遠超過了更快的用戶界面可以顯示它們。 它可能起步不錯,但隨着時間的流逝會越來越糟。 您強制TextBox重新分配內存以查找附加字符串的空間,復制原始文本並附加新文本。 一旦文本框包含兆字節的文本(贈送或接受),這將嚴重開始拖累。 System.String類具有相同的問題。 它具有StringBuilder作為修復程序,而TextBox沒有任何相似之處。
通常的症狀是UI線程將開始刻錄100%的內核。 在某個關鍵時刻,它完全崩潰了,不再重繪UI並對輸入無響應。 因為每次更新Text屬性,它都有另一個委托要調用。 沒有時間再進行優先級較低的工作了,例如繪制和清空消息隊列。 調用隊列本身開始落后,收集越來越多的等待處理的調用請求。 在極端情況下,這將使您的程序因OutOfMemoryException崩潰,但這會花費很長時間。 即使后台工作人員完成操作,此后,UI線程也忙了很長時間,試圖減少積壓工作。
用戶界面通常無法正常使用,甚至在碰壁之前也無法使用。 用戶只是盯着一個盲目的快速滾動的文本框,該文本框不允許實際讀取任何內容。 本身使用文本框會適得其反,對於用戶編輯列表沒有任何意義。
顯然,您需要以不同的方式執行此操作。 在調用之前,至少要在StringBuilder中收集一堆文件。 這將使TextBox不必經常重新分配。 每隔50毫秒調用一次就沒有任何意義了,這幾乎相當於人眼看到變化而不會變得模糊的速度。 大多數執行此操作的程序僅顯示迭代的文件示例 ,以便用戶對進度有一些反饋。 在這種情況下,將所有數據收集在StringBuilder中並且在文件迭代完成之前不更新TextBox是完全合理的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.