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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > C# >内容正文

C#

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

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

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

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

三.
后臺(tái)耗時(shí)任務(wù)
在后臺(tái)執(zhí)行一個(gè)不可分解的耗時(shí)任務(wù),需要進(jìn)行界面更新,以便讓客戶看上去程序有所響應(yīng)。這種情況下,UI線程一般也不知道工作線程何時(shí)結(jié)束,所以一般執(zhí)行循環(huán)任務(wù),當(dāng)工作線程結(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ǎn):線程調(diào)用的方法都不能訪問用戶控件,必須通過委托調(diào)用Form的方法來實(shí)現(xiàn)界面更新。

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

?

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);//模擬耗時(shí)UI任務(wù),非循環(huán),不可分解

?


}

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

2.
Application.DoEvent
在耗時(shí)的循環(huán)的UI更新的方法中,插入Application.DoEvent,會(huì)使界面獲得響應(yīng),Application.DoEvent會(huì)調(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)
{
}
等價(jià)與

?

try

?

?


{

?

?


Monitor.Enter(object);

?

?


}

?

?


finally

?

?


{

?

?


Monitor.Exit(object)

?


}

附一:

?

BackgroundWorker組件使用說明

?

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

二.
基本屬性

?

1.
WorkerReportsProgress?,bool:是否允許報(bào)告進(jìn)度;

?

?

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

?

?

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

?

?

?

?

三.
基本事件

?

1.
DoWork:工作者線程

?

?

2.
RunWorkerCompleted?:線程進(jìn)度報(bào)告

?

?

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

?


四.
基本方法

?

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

?

?

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

?

?

3.
ReportProgress(int);
報(bào)告進(jìn)度

?


五.
代碼

?

//啟動(dòng)

?

?

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);
//干點(diǎn)實(shí)際的事

?

?

?

?

?


backgroundWorker.ReportProgress(i);
//報(bào)告進(jìn)度

?

?


}

?

?

}

?

?

?

?

?

//線程進(jìn)度報(bào)告

?

?

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

?

?

{

?

?


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

?

?

}

?

?

?

?

?

//線程結(jié)束報(bào)告

?

?

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)容還不錯(cuò),歡迎將生活随笔推薦給好友。