簡體   English   中英

UI線程中的ProgressBar更新

[英]ProgressBar updates in blocked UI thread

為什么ProgressBar在理論上被阻止的UI線程中更新?

在簡單的應用程序中,我有一個ProgressBar和一個Label。 我在UI線程中運行一個耗時的方法,該方法試圖更新ProgressBar和標簽。 這是應該工作,因為阻塞UI線程的。 但是ProgressBar正在更新!

在對表單執行任何操作並將其凍結之前,ProgressBar會更新(標簽不會)。

這是為什么?

示例代碼(在窗體上放置一個Button,一個ProgressBar和一個Label):

private void button1_Click(object sender, EventArgs e)
{
    while (true)
    {
        progressBar1.Value += 1;
        label1.Text += "1";
        Thread.Sleep(100);
    }
}

ProgressBar正在更新,Label沒有更新。 我的問題不是如何同時更新標簽,而是為什么更新ProgressBar。 我確實了解線程,DoEvent,異步/等待,但這不是答案。

我認為在不拆卸Windows的情況下很難完全回答這個問題,這對我來說現在太繁瑣了。

但是基本上,當您在WinForms ProgressBar控件上設置.Value時,它所做的只是調用帶有消息1026(PBM_SETPOS)的SendMessage,它告訴Windows進度欄設置其位置。

我可以得出結論,Windows進度條響應PBM_SETPOS 以及 WM_PAINT同步重新繪制自己。 或許它正在另一個線程上運行計時器以執行炫目的眩光動畫,並且無需等待繪制消息即可重繪控件。

無論哪種方式,它只是Windows內部,你所看到的-和WM_PAINT處理程序外畫的東西不是一個不尋常的技術,盡管它不是做事情的教科書的方式。

實際上,查看PBM_SETPOS的文檔( http://msdn.microsoft.com/zh-cn/library/bb760844(v=vs.85).aspx ),該文檔被記錄為導致重畫-我想這是故意為幫助懶惰/缺乏經驗的人阻止進度條更新,以正常進行工作,而無任何通常的麻煩。

有不同的方法來回答您的問題。 讓我解釋。 如果您正在運行一個漫長的任務,而用戶必須等待才能繼續,那么實際上是否在UI線程上運行都無關緊要。 無論哪種方式,用戶都必須等待任務完成才能繼續,因此他們仍然無法使用該應用程序。

但是,在您可能希望用戶在任務運行時與應用程序的不同部分進行交互的操作中,您會創建一個工作線程來執行所述任務。 您需要了解主UI線程是用於處理UI的。 繪制進度條是UI的一部分。 WinForms / .NET的設計體系結構是您可以通過BackgroundWorker類創建后台線程,或者自行連接原始線程。 其設計。

但是,所有這些都將在帶有async和await關鍵字以及Task對象的C#5.0中發生劇烈變化。 您可以在channel9上搜索TechDays 11,或訪問我的Facebook (有關它的幾篇文章已發布)。

如果您傾向於在任務中保持對UI線程調用Application.DoEvents()的操作以保持Windows消息的暢通,則可以幫助糾正您的情況,或者可以采取正確的方法並正確地實現線程。 它非常容易使用Thread類進行連接,委托和調用,甚至更易於使用BackgroundWorker,該BackerWorker的設計宗旨是在另一個線程上執行任務並報告0/100%的漸進值。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM