![](/img/trans.png)
[英]BackgroundWorker with ProgressBar - Cross-thread operation not valid
[英]BackgroundWorker - Cross-thread operation not valid
我有一個winform應用程序(一個表單),在這個表單上有一個RichTextBox。 在這個窗體的構造函數中,我創建了一個MyClass
類的實例。 在“Form_Load”中,我從MyClass
實例調用Initialisation
方法。
在表單構造函數中
myClass = new MyClass(RichTextBox richTextBox);
在Form_Load中
myClass.Initialisation();
在Initialisation
方法中,在循環中,我讀了一些參數做其他的東西。 要不凍結應用程序(因為某些操作可能需要一段時間,幾秒鍾),我使用BackgroundWorker
。 我這樣使用它(見下面的代碼)。
當我執行時,我收到此錯誤: 跨線程操作無效:控制'richTextBox'從其創建的線程以外的線程訪問 。
你能告訴我怎么解決這個問題嗎? 當我不訪問richTextBox
時,工作完美
public Class MyClass
{
static BackgroundWorker _bw;
public MyClass()
{
_bw = new BackgroundWorker
{
WorkerReportsProgress = true,
WorkerSupportsCancellation = true
};
_bw.DoWork += bw_DoWork;
_bw.ProgressChanged += bw_ProgressChanged;
_bw.RunWorkerCompleted += bw_RunWorkerCompleted;
}
static void bw_DoWork(object sender, DoWorkEventArgs e)
{
foreach (....)
{
if (....)
{
richtextBox.Text.AppendText("MyText");
}
}
e.Result = true;
}
static void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e){}
static void bw_ProgressChanged(object sender, ProgressChangedEventArgs e){}
}
使用BackgroundWorker
並不能免除正常的線程規則 - 例如只有 UI線程才能訪問UI組件。
如果要從BackgroundWorker
更新UI而不是使用進度/完成事件(在UI線程上引發),則需要像在其他情況下一樣使用Control.Invoke
/ Control.BeginInvoke
。 例如:
if (....)
{
Action action = () => richtextBox.Text.Add("MyText");
richtextBox.Invoke(action); // Or use BeginInvoke
}
試試這段代碼,
BeginInvoke((MethodInvoker)delegate
{
richtextBox.Text.Add("MyText");
});
使用BackgroundWorker組件,只有ProgressChanged
和RunWorkerCompleted
事件允許您調用UI控件上的方法/屬性(應始終在UI線程上完成)。 當您在非UI線程上運行的DoWork
事件中更新UI時,您會收到此錯誤,如果您願意,您應該使用DoWork事件中的Invoke或BeginInvoke方法更新UI控件。
為了使它更干凈並且基於Jon Skeet的建議,我做了一個擴展方法,它做了同樣的事情,你可以將“ this Label control
”更改為this TextBox control
或簡單地使用“ this Control control
”(並且基本上允許每個控件都是輕松更新):
internal static class ExtensionMethods
{
/// <summary>
/// Updates the label text while being used in a multithread app.
/// </summary>
/// <param name="control">The control.</param>
/// <param name="text">The text.</param>
internal static void UpdateThreadedText(this Label control, string text)
{
Action action = () => control.Text = text;
control.Invoke(action);
}
/// <summary>
/// Refreshes the threaded.
/// </summary>
/// <param name="control">The control.</param>
internal static void RefreshThreaded(this Label control)
{
Action action = control.Refresh;
control.Invoke(action);
}
}
然后用法非常簡單:
this.yourLabelName.UpdateThreadedText("This is the text");
this.yourTextBoxName.UpdateThreadedText("This is the text");
this.yourControlName.UpdateThreadedText("This is the text");
要么
this.yourLabelName.RefreshThreaded();
很適合我:)
你也可以試試這個。
this.Invoke(new MethodInvoker(delegate()
{
richtextBox.Text.Add("MyText");
}));
加:
e.Result = "MyText";
在你的bw_DoWork
:
richTextBox1.AppendText((string)e.Result);
在你的bw_RunWorkerCompleted
(改變它以適合您的代碼)
編輯:
如果在BackgroundWorker
工作期間多次完成,您可以添加:
_bw.ReportProgress(0, "MyText");
到bw_DoWork
並:
richTextBox1.AppendText((string)e.UserState);
到bw_ProgressChanged
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.