在開發`winfrom`應用時,經常遇到異常:`System.InvalidOperationException:“線程間操作無效: 從不是創建控制項“xxxx”的線程訪問它。`出現這個異常的原因是創建這個UI的線程,和當前訪問這個UI的線程不會是同一個。Winform為了防止線程不安全,因此對這個跨... ...
在開發winfrom
應用時,經常遇到異常:System.InvalidOperationException:“線程間操作無效: 從不是創建控制項“xxxx”的線程訪問它。
出現這個異常的原因是創建這個UI的線程,和當前訪問這個UI的線程不會是同一個。Winform為了防止線程不安全,因此對這個跨線程訪問拋出異常,禁止這個操作。
解決方案
使用InvokeRequired
屬性判斷是否線程安全。
if (richTextBox1.InvokeRequired)
{
richTextBox1.Invoke(new Action(() =>
{
richTextBox1.AppendText(log);
richTextBox1.AppendText("\r\n");
}));
}
else
{
richTextBox1.AppendText(log);
richTextBox1.AppendText("\r\n");
}
如果richTextBox1是在非主線程
創建或找不到其句柄,那麼richTextBox1.InvokeRequired=false
返回false,就會走else分支,如果在找不到句柄的情況下,else里的代碼也會拋異常。為了更加安全,需要進一步對句柄進行判斷,用IsHandleCreated
判斷是否創建了句柄。
if (richTextBox1.InvokeRequired)
{
richTextBox1.Invoke(new Action(() =>
{
richTextBox1.AppendText(log);
richTextBox1.AppendText("\r\n");
}));
}
else
{
if (richTextBox1.IsHandleCreated)
{
richTextBox1.AppendText(log);
richTextBox1.AppendText("\r\n");
}
}
上面代碼基本上沒什麼問題了。但是稍顯麻煩,可以進行精簡一下。使用哦當前Form
的Invoke
方法而不是具體某個Control
的Invoke
,這樣能確保當前的操作一定在當前的UI線程中,且句柄一併被創建。
private void Log(string log)
{
Invoke(new Action(() =>
{
richTextBox1.AppendText(log);
richTextBox1.AppendText("\r\n");
}));
}
其實在winform
中跨線程訪問UI很常見,比如在一個子視窗中進行了某個操作,需要更新主視窗里的某些狀態或數據,如果稍不註意就會出現跨線程訪問UI的異常,因此Invoke
方法應該被廣泛使用。
本文來自博客園,作者:宣君{https://www.nhit.icu/},轉載請註明原文鏈接:https://www.cnblogs.com/ycit/p/17621798.html