日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > C# >内容正文

C#

C#多线程与UI响应 防止界面假死不响应(子线程创建的窗体获取消息响应用Application.DoEvent )

發(fā)布時間:2023/12/18 C# 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C#多线程与UI响应 防止界面假死不响应(子线程创建的窗体获取消息响应用Application.DoEvent ) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

一.
概述
在使用C#進行應用程序設(shè)計時,經(jīng)常會采用多線程的方式進行一些后臺任務(wù)的工作。對于不同的應用場景,使用的策略也不盡相同。
1.
后臺循環(huán)任務(wù),少量UI更新:例如批量上傳文件,并提供進度。這種情況使用BackgroundWorker組件是非常好的選擇。
2.
耗時的后臺任務(wù):這里的耗時任務(wù)是指一個時間較長的任務(wù),并且不能精確獲取進度,如:調(diào)用一個遠程WebService接口。這種情況可以開兩個線程,一個工作,一個更新UI(不能提供進度,只能顯示動畫表示系統(tǒng)在運行中)。
3.
耗時的UI任務(wù):當工作壓力集中在UI響應上時,可以在工作者線程中增加延時,從而讓UI線程獲得響應時間。整個工作的總體時間會增加,但用戶響應效果會好很多。

二.
后臺的循環(huán)任務(wù),少量UI更新
這種情況使用BackgroundWorker組件是最好的選擇。(詳見附一)

三.
后臺耗時任務(wù)
在后臺執(zhí)行一個不可分解的耗時任務(wù),需要進行界面更新,以便讓客戶看上去程序有所響應。這種情況下,UI線程一般也不知道工作線程何時結(jié)束,所以一般執(zhí)行循環(huán)任務(wù),當工作線程結(jié)束后,關(guān)閉UI線程就可以了。

?

Thread?uithread =?null;

?

?


private?void?btnStart_Click(object?sender,?EventArgs?e)

?

?


{

?

?


uithread =?new?Thread(new?ThreadStart(this.UpdateProgressThread));

?

?


uithread.Start();

?

?

?

?

?


Thread?workthread =?new?Thread(new?ThreadStart(this.DoSomething));

?

?



workthread.Start();

?

?


}

?

?

?

?

?


private?void?DoSomething()

?

?


{

?

?


Thread.Sleep(5000);

?

?



uithread.Abort();

?

?


MessageBox.Show("work end");

?

?


}

?

?

?

?

?


private?void?UpdateProgressThread()

?

?


{

?

?


for?(int?i = 0; i < 10000; i++)

?

?


{

?

?


Thread.Sleep(100);

?

?


this.Invoke(new?Action<int>(this.UpdateProgress), i);

?

?


}

?

?


}

?

?

?

?

?


private?void?UpdateProgress(int?v)

?

?


{

?

?



this.progressBar1.Value = v;

?


}

這里只要注意一點:線程調(diào)用的方法都不能訪問用戶控件,必須通過委托調(diào)用Form的方法來實現(xiàn)界面更新。

四.
耗時的UI任務(wù)
當整個工作壓力集中在UI響應上時,可以在工作者線程中增加延時,從而讓UI線程獲得響應時間。整個工作的總體時間會增加,但用戶響應效果會好很多。

?

private?void?FormInitForm_Load(object?sender,?EventArgs?e)

?

?


{

?

?


this.listView1.Items.Clear();

?

?


Thread?workthread =?new?Thread(new?ThreadStart(this.DoSomething));

?

?


workthread.Start();

?

?


}

?

?

?

?

?


private?void?DoSomething()

?

?


{

?

?


for?(int?i = 0; i < 30; i++)

?

?


{

?

?


this.Invoke(new?Action<int>(this.LoadPicture), i);

?

?


Thread.Sleep(100);

?

?


}

?

?


}

?

?

?

?

?


private?void?LoadPicture(int?i)

?

?


{

?

?


string?text =?string.Format("Item{0}", i);

?

?


ListViewItem?lvi =?new?ListViewItem(text, 0);

?

?


this.listView1.Items.Add(lvi);

?

?


Thread.Sleep(200);//模擬耗時UI任務(wù),非循環(huán),不可分解

?


}

五.
補充
1.
Invoke?和?BeginInvoke
在多線程編程中,我們經(jīng)常要在工作線程中去更新界面顯示,而在多線程中直接調(diào)用界面控件的方法是錯誤的做法,正確的做法是將工作線程中涉及更新界面的代碼封裝為一個方法,通過?Invoke?或者?BeginInvoke?去調(diào)用,兩者的區(qū)別就是一個導致工作線程等待,而另外一個則不會。
而所謂的“一面響應操作,一面添加節(jié)點”永遠只能是相對的,使?UI?線程的負擔不至于太大而以,因為界面的正確更新始終要通過?UI?線程去做,我們要做的事情是在工作線程中包攬大部分的運算,而將對純粹的界面更新放到?UI?線程中去做,這樣也就達到了減輕?UI?線程負擔的目的了。

2.
Application.DoEvent
在耗時的循環(huán)的UI更新的方法中,插入Application.DoEvent,會使界面獲得響應,Application.DoEvent會調(diào)用消息處理程序。

?

private?void?button2_Click(object?sender,?EventArgs?e)

?

?


{

?

?


for?(int?i = 0; i < 30; i++)

?

?


{

?

?


string?text =?string.Format("Item{0}", i);

?

?


ListViewItem?lvi =?new?ListViewItem(text, 0);

?

?


this.listView1.Items.Add(lvi);

?

?


Thread.Sleep(200);

?

?


for?(int?j = 0; j < 10; j++)

?

?


{

?

?


Thread.Sleep(10);

?

?


Application.DoEvents();

?

?


}

?

?


}

?


}
3.
Lock
lock(object)
{
}
等價與

?

try

?

?


{

?

?


Monitor.Enter(object);

?

?


}

?

?


finally

?

?


{

?

?


Monitor.Exit(object)

?


}

附一:

?

BackgroundWorker組件使用說明

?

一.
概述
BackgroundWorker是·NET 2.0提供的一個多線程組件,在應用程序中使用,可以非常簡單方便地實現(xiàn)UI控件通信,并自動處理多線程沖突問題。

二.
基本屬性

?

1.
WorkerReportsProgress?,bool:是否允許報告進度;

?

?

2.
WorkerSupportsCancellation,bool:是否允許取消線程。

?

?

3.
CancellationPending,bool,get:讀取用戶是否取消該線程。

?

?

?

?

三.
基本事件

?

1.
DoWork:工作者線程

?

?

2.
RunWorkerCompleted?:線程進度報告

?

?

3.
ProgressChanged:線程結(jié)束報告

?


四.
基本方法

?

1.
RunWorkerAsync()?:啟動工作者線程;

?

?

2.
CancelAsync():取消工作者線程;

?

?

3.
ReportProgress(int);
報告進度

?


五.
代碼

?

//啟動

?

?

private?void?btnStart_Click(object?sender,?EventArgs?e)

?

?

{

?

?


this.btnStart.Enabled =?false;

?

?


this.btnStop.Enabled =?true;

?

?

?

?

?


this.backgroundWorker.RunWorkerAsync();

?

?

}

?

?

?

?

?

//通知線程停止

?

?

private?void?btnStop_Click(object?sender,?EventArgs?e)

?

?

{

?

?


this.backgroundWorker.CancelAsync();

?

?

}

?

?

?

?

?

//工作者線程

?

?

private?void?backgroundWorker_DoWork(object?sender,?DoWorkEventArgs?e)

?

?

{

?

?


for?(int?i = 0; i < 150; i++)

?

?



{

?

?


if?(backgroundWorker.CancellationPending)
//查看用戶是否取消該線程

?

?


{

?

?


break;

?

?


}

?

?

?

?

?


System.Threading.Thread.Sleep(50);
//干點實際的事

?

?

?

?

?


backgroundWorker.ReportProgress(i);
//報告進度

?

?


}

?

?

}

?

?

?

?

?

//線程進度報告

?

?

private?void?backgroundWorker_ProgressChanged(object?sender,?ProgressChangedEventArgs?e)

?

?

{

?

?


this.progressBar1.Value = e.ProgressPercentage * 100 / 150;

?

?

}

?

?

?

?

?

//線程結(jié)束報告

?

?

private?void?backgroundWorker_RunWorkerCompleted(object?sender,?RunWorkerCompletedEventArgs?e)

?

?

{

?

?


this.btnStart.Enabled =?true;

?

?


this.btnStop.Enabled =?false;

?

}

總結(jié)

以上是生活随笔為你收集整理的C#多线程与UI响应 防止界面假死不响应(子线程创建的窗体获取消息响应用Application.DoEvent )的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。