[C#] 在 GUI 中執行非同步操作

来源:http://www.cnblogs.com/liqingwen/archive/2016/09/17/5877042.html
-Advertisement-
Play Games

在 GUI 中執行非同步操作 序 目錄 一、在 GUI 程式中執行非同步操作 下麵通過窗體示例演示以下操作-點擊按鈕後:①將標簽內容改成:“Doing”,並將按鈕禁用(表示執行中);②線程掛起3秒(模擬耗時操作);③將標簽內容改為:“Complete”,並啟用按鈕(表示執行完成); 可是執行結果卻是: ...


在 GUI 中執行非同步操作

 

 

目錄

 

一、在 GUI 程式中執行非同步操作

  下麵通過窗體示例演示以下操作-點擊按鈕後:①將標簽內容改成:“Doing”,並將按鈕禁用(表示執行中);②線程掛起3秒(模擬耗時操作);③啟用按鈕,將標簽內容改為:“Complete”(表示執行完成);

 1     public partial class Form1 : Form
 2     {
 3         public Form1()
 4         {
 5             InitializeComponent();
 6         }
 7 
 8         private void btnDo_Click(object sender, EventArgs e)
 9         {
10             btnDo.Enabled = false;
11             lblText.Text = @"Doing";
12 
13             Thread.Sleep(3000);
14 
15             btnDo.Enabled = true;
16             lblText.Text = @"Complete";
17         }
18     }

  可是執行結果卻是:

圖1-1

 

  發現的問題:好像沒有變成“Doing”,並且拖動視窗的時候卡住不動了,3秒後突然變到想拖動到的位置,並且文本變成“Complete”?

  【分析】GUI 程式在設計中要求所有的顯示變化都必須在主 GUI 線程中完成,如點擊事件和移動窗體。Windows 程式時通過 消息來實現,消息放入消息泵管理的消息隊列中。點擊按鈕時,按鈕的Click消息放入消息隊列。消息泵從隊列中移除該消息,並開始處理點擊事件的代碼,即 btnDo_Click 事件的代碼。btnDo_Click 事件會將觸發行為的消息放入隊列,但在 btnDo_Click 時間處理程式退出前(線程掛起 3 秒退出前),消息都無法執行。接著所有行為都發生了,但速度太快肉眼分辨不了。

圖1-2 點擊事件

圖1-3 點擊事件具體執行過程

  

  現在我們加入 async/await 特性。

 1     public partial class Form1 : Form
 2     {
 3         public Form1()
 4         {
 5             InitializeComponent();
 6         }
 7 
 8         private async void btnDo_Click(object sender, EventArgs e)
 9         {
10             btnDo.Enabled = false;
11             lblText.Text = @"Doing";
12 
13             await Task.Delay(3000);
14 
15             btnDo.Enabled = true;
16             lblText.Text = @"Complete";
17         }
18     }

圖1-4

  現在,就是原先希望看到的效果。

  【分析】btnDo_Click 事件處理程式先將前兩條消息壓入隊列,然後將自己從處理器移出,在3秒後(等待空閑任務完成後 Task.Delay )再將自己壓入隊列。這樣可以保持響應,並保證所有的消息可以線上程掛起的時間內被處理。

 

 1.1 Task.Yield

  Task.Yield 方法創建一個立刻返回的 awaitable。等待一個Yield可以讓非同步方法在執行後續部分的同時返回到調用方法。可以將其理解為 離開當前消息隊列,回到隊列末尾,讓 CPU 有時間處理其它任務。

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             const int num = 1000000;
 6             var t = DoStuff.Yield1000(num);
 7 
 8             Loop(num / 10);
 9             Loop(num / 10);
10             Loop(num / 10);
11 
12             Console.WriteLine($"Sum: {t.Result}");
13 
14             Console.Read();
15         }
16 
17         /// <summary>
18         /// 迴圈
19         /// </summary>
20         /// <param name="num"></param>
21         private static void Loop(int num)
22         {
23             for (var i = 0; i < num; i++) ;
24         }
25     }
26 
27     internal static class DoStuff
28     {
29         public static async Task<int> Yield1000(int n)
30         {
31             var sum = 0;
32             for (int i = 0; i < n; i++)
33             {
34                 sum += i;
35                 if (i % 1000 == 0)
36                 {
37                     await Task.Yield(); //創建非同步產生當前上下文的等待任務
38                 }
39             }
40 
41             return sum;
42         }
43     }

 圖1.1-1

  上述代碼每執行1000次迴圈就調用 Task.Yield 方法創建一個等待任務,讓處理器有時間處理其它任務。該方法在 GUI 程式中非常有用。

 

二、使用非同步 Lambda 表達式

  將剛纔的視窗程式的點擊事件稍微改動一下。

 1     public partial class Form1 : Form
 2     {
 3         public Form1()
 4         {
 5             InitializeComponent();
 6 
 7             //async (sender, e) 非同步表達式
 8             btnDo.Click += async (sender, e) =>
 9             {
10                 Do(false, "Doing");
11 
12                 await Task.Delay(3000);
13 
14                 Do(true, "Finished");
15             };
16         }
17 
18         private void Do(bool isEnable, string text)
19         {
20             btnDo.Enabled = isEnable;
21             lblText.Text = text;
22         }
23     }

  還是原來的配方,還是熟悉的味道,還是原來哪個視窗,變的只是內涵。

圖2-1

 

 三、完整的 GUI 程式

  

 


【原文地址】http://www.cnblogs.com/liqingwen/p/5877042.html 

 ========預覽版,整理完畢後發佈到首頁=========


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 文本查找 grep,egrep,fgrep grep :Global Research 根據模式搜索文本,並將符合模式的文本行顯示出來 模式:Pattern,文本字元和正則的元字元組合而成匹配條件 grep 'root' /etc/passwd -i :ignore case,忽略大小寫 --col ...
  • 1.安裝git 2.創建用戶與授權 3.git 使用 ...
  • 1.安裝vsftpd 2.配置vsftpd.conf 3.添加ftp用戶 4.上傳許可權 5.設置vsftp 開機啟動 6.添加防火牆 ...
  • 每個人心裡都有一個建站夢,所以今天作為我第一篇文章,就給大家圓了這場夢。 今天我來詳細的一步一步帶領大家利用WordPress程式來建立自己的小站以及解決直接功能變數名稱訪問(本地安裝wordpress請閱讀《本地安裝WordPress》),首先建議大家在跟著我的步驟準備開始的時候先看看我的另一篇文章《Wo ...
  • I/O: 系統設定 預設輸入設備:標準輸入,STDIN,0 預設輸出設備:標準輸出,STDOUT,1 標準錯誤輸出:STDERR,2 屬於不同的數據流 標準輸入:鍵盤 標準輸出和錯誤輸出:顯示器 I/O重定向: 輸出重定向: > :覆蓋輸出 >> :追加輸出 2>:錯誤輸出 2>>:追加錯誤輸出 正 ...
  • ColorConsole htmlagilitypack.1.4.9.5 經測試效率比 CsQueryLaster 高 csvhelper Extend Devlib系列一套 itextsharp litedb log4net microsoft.bcl一套,.net4 await 用 MySql.... ...
  • 分別使用Controller和Filter方法完成登錄驗證,對比二者的優劣 ...
  • 分析ASP.NET MVC中隱藏處理的方法,使用記憶體隊列記錄日誌防止併發錯誤,Log4Net的使用方法及簡單應用 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...