<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      C#之BackgroundWorker從簡單入門到深入精通的用法總結

      需求分析

      經常用到的耗時操作,例如:

      1、文件下載和上載(包括點對點應用程序傳輸文件,從網絡下載文件、圖像等)
      2、數據庫事務(從數據庫讀到大量的數據到WinForm界面中的DataGridview里呈現)
      3、復雜的本地計算
      4、本地磁盤文件訪問(讀寫文件,磁盤文件列表)
      ……

      這些操作在長時間運行時會導致用戶界面 (UI) 處于停止響應狀態,用戶在這操作期間無法進行其他的操作,造成非常差的用戶體驗,為了不使UI層處于停止響應狀態,則可以使用 BackgroundWorker 類方便地解決這類問題。這個后臺的線程處理,可以很好的實現常規操作的同時,還可以及時通知UI當前處理信息的進度等。


      MSDN的介紹

      BackgroundWorker是.NET Framework 里用來執行多線程任務的控件,它允許開發人員在一個單獨的線程上執行一些操作。耗時的操作(如下載和數據庫事務)在長時間運行時可能會導致用戶界面 (UI) 似乎處于停止響應狀態。 如果您需要能進行響應的用戶界面,而且面臨與這類操作相關的長時間延遲,則可以使用 BackgroundWorker 類方便地解決問題。

      若要在后臺執行耗時的操作,請創建一個 BackgroundWorker,偵聽那些報告操作進度并在操作完成時發出信號的事件。 可以通過編程方式創建 BackgroundWorker,也可以將它從“工具箱”的“組件”選項卡中拖到窗體上。 如果在 Windows 窗體設計器中創建 BackgroundWorker,則它會出現在組件欄中,而且它的屬性會顯示在“屬性”窗口中。

      若要為后臺操作做好準備,請添加 DoWork 事件的事件處理程序。 在此事件處理程序中調用耗時的操作。 若要開始此操作,請調用 RunWorkerAsync。 若要收到進度更新的通知,請處理 ProgressChanged 事件。 若要在操作完成時收到通知,請處理 RunWorkerCompleted 事件。

      有2點需要注意的:

      1、由于DoWork事件內部的代碼運行在非UI線程之上,確保在 DoWork 事件處理程序中不操作任何用戶界面對象。 而應該通過 ProgressChanged 和 RunWorkerCompleted 事件與用戶界面進行通信。
      2、BackgroundWorker 事件不跨 AppDomain 邊界進行封送處理。 請不要使用 BackgroundWorker 組件在多個 AppDomain 中執行多線程操作。

       

      最簡單示例

      準備材料:一個耗時的操作

       代碼如下,這個就不多解釋了:

      int iSum = 0; 
      private void button1_Click(object sender, EventArgs e)
       {   
        for (int i = 0; i <= 100; i++)
         { 
           iSum+=i; 
           System.Threading.Thread.Sleep(300);   
         }
      }
      

       運行一下,拖動程序界面看看,直接卡死了,假死,一會兒,運算完了,就又可以拖動了。現在用BackgroundWorker來解決這個問題。

       為此,我們新建一個WindowsForm命名為bgwA,拖入一個Label命名為lblPercent,一個ProgressBar命名為pgbPercent,一個Button命名為btnStart。

       

      然后,代碼:

      using System;
      using System.Collections.Generic;
      using System.ComponentModel;
      using System.Data;
      using System.Drawing;
      using System.Linq;
      using System.Text;
      using System.Threading.Tasks;
      using System.Windows.Forms;
      
      namespace bgwA
      {
          public partial class Form1 : Form
          {
              public Form1()
              {
                  InitializeComponent();
              }
      
              private void BtnStart_Click(object sender, EventArgs e)
              {
                  BackgroundWorker bgwA = new BackgroundWorker();
                  bgwA.WorkerReportsProgress = true;
                  bgwA.DoWork += bgwA_DoWork;
                  bgwA.ProgressChanged += bgwA_ProgressChanged;
                  bgwA.RunWorkerCompleted += bgwA_Completed;
                  bgwA.RunWorkerAsync();
              }
      
              private void bgwA_DoWork(object sender, DoWorkEventArgs e)
              {
                  var bgworker = sender as BackgroundWorker;
                  for (int i = 0; i <= 100; i++)
                  {
                      bgworker.ReportProgress(i);
                      System.Threading.Thread.Sleep(200);
                  }
              }
      
              private void bgwA_ProgressChanged(object sender, ProgressChangedEventArgs e)
              {
                  this.pgbPercent.Value = e.ProgressPercentage;
                  this.lblPercent.Text = @"已完成:" + e.ProgressPercentage.ToString() + @"%";
              }
              private void bgwA_Completed(object sender, RunWorkerCompletedEventArgs e)
              {
                  this.lblPercent.Text = "后臺操作結束(可能是程序100%完成,也可能是用戶取消或程序異常導致結束)。";
              }
          }
      }
      

        現在運行一下,點擊btnStart,進度條跑起來了,再拖動一下程序界面,這下不會沒有響應了,不卡,不假死了吧。good.

       

      進階一:

       重復上面說到的注意點:由于DoWork事件內部的代碼運行在非UI線程之上,確保在 DoWork 事件處理程序中不操作任何用戶界面對象。 而應該通過 ProgressChanged 和 RunWorkerCompleted 事件與用戶界面進行通信。

       

      如何在程序運行途中取消正在進行的運算?

      要實現在這個功能,我們首先在程序界面上添加一個可以隨時中止后臺進程的按鈕BtnCancel,允許用戶在執行過程中取消當前的操作:

      與WorkerReportsProgress屬性一樣,如果要支持取消操作我們需要設置 WorkerSupportsCancellation屬性為 true,還要在DoWork方法中進行支持。

      接下來對上面的程序進行擴展一下,我們再新建一個WindowsForm命名為bgwB,這次,我們不再通過代碼來寫BackgroundWorker實例,我們通過從VS的工具箱中直接拉一個BackgroundWorker出來,然后從屬性窗口中命名為bgWorker,然后再拖入一個Label命名為lblPercent,一個ProgressBar命名為pgbPercent,一個Button命名為btnStart。

       

       

       DoWork,ProgressChanged,RunWorkerCompleted三個事件都是通過在bgWorker1屬性窗口中雙擊出來的,下面看代碼:

       

      using System;
      using System.Collections.Generic;
      using System.ComponentModel;
      using System.Data;
      using System.Drawing;
      using System.Linq;
      using System.Text;
      using System.Threading.Tasks;
      using System.Windows.Forms;
      
      namespace bgwB
      {
          public partial class Form1 : Form
          {
              public Form1()
              {
                  InitializeComponent();
              }
      
              private void Form1_Load(object sender, EventArgs e)
              {
                  bgWorker1.WorkerReportsProgress = true;
                  bgWorker1.WorkerSupportsCancellation = true;
              }
      
              private void BgWorker1_DoWork(object sender, DoWorkEventArgs e)
              {
                  for (int i = 0; i <= 100; i++)
                  {
                      if (bgWorker1.CancellationPending == true)
                      {
                          e.Cancel = true;
                          break;
                      }
                      else
                      {
                          bgWorker1.ReportProgress(i);
                          System.Threading.Thread.Sleep(100);
                      }
                  }
              }
      
              private void BgWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
              {
                  this.pgbPercent.Value = e.ProgressPercentage;
                  this.lblPercent.Text = @"已完成:" + e.ProgressPercentage.ToString() + @"%";
              }
      
              private void BgWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
              {
                  this.lblPercent.Text = "后臺操作結束(可能是程序100%完成,也可能是用戶取消或程序異常導致結束)。";
              }
      
              private void BtnStart_Click(object sender, EventArgs e)
              {
                  bgWorker1.RunWorkerAsync();
              }
      
              private void BtnCancel_Click(object sender, EventArgs e)
              {
                  bgWorker1.CancelAsync();
              }
          }
      }
      

        現在,我們可以按BtnStart啟動后臺任務,也可以隨時按BtnCancel隨時中止后臺任務。

       

       

      發現一個問題沒有?在進度條還沒跑完100%時,再次按btnStart會怎么樣,前后兩個例子是不一樣,第一個例子中,再次按btnStart,會感覺有兩個重疊的進度條在跑,而第二個例子中,則直接拋出了異常:

      為什么會這樣?第一個例子中,每次按btnStart,都是BackgroundWorker bgwA = new BackgroundWorker();而第二個例子中每次按btnStart,還是那個bgWorker1,只是再次RunWorkerAsync(),解決的方法是先判斷一下后臺操作是否還在運行中:IsBusy

      代碼:

              private void BtnStart_Click(object sender, EventArgs e)
              {
                  if (!bgWorker1.IsBusy)
                  {
                      bgWorker1.RunWorkerAsync();
                  }
              }
      

      小結一下:

      BackgroundWorker的屬性

      IsBusy:獲取一個值(true/false),指示 BackgroundWorker 是否正在運行異步操作。

      WorkerReportsProgress:獲取或設置一個值(true/false),該值指示 BackgroundWorker 能否報告進度更新。

      WorkerSupportsCancellation:獲取或設置一個值(true/false),該值指示 BackgroundWorker 是否支持異步取消。

      BackgroundWorker事件

      DoWork:調用 RunWorkerAsync 時發生。(要在后臺進行的耗時操作,不能操作任何用戶界面對象。)

      ProgressChanged:調用 ReportProgress 時發生。(后臺操作進行時,隨時向用戶界面報告進度,可以操作用戶界面對象,如進度條顯示,文本顯示等。)

      RunWorkerCompleted:當后臺操作已完成、被取消或引發異常時發生。(可以操作用戶界面對象,如顯示完成的結果報告。)

       

        

      進階二:前后臺交互,參數傳遞

       
      先來看兩個問題,再來處理
      1、BackgroundWorker的ProgressChanged向用戶界面報告的ProgressPercentage,只是一個百分比,這個百分比數只能是 int 0-100 ,我們前面的例子中是從0循環到100,到100是剛好100%完成,如果我們要循環的是從0-50,或0-200,或其它不確定的數呢?把DoWork中for (int i = 0; i <= 100; i++)的100,改成50或200試試?
              private void BgWorker1_DoWork(object sender, DoWorkEventArgs e)
              {
                  for (int i = 0; i <= 50; i++)
                  {
                      if (bgWorker1.CancellationPending == true)
                      {
                          e.Cancel = true;
                          break; 
                      }
                      else
                      {
                          bgWorker1.ReportProgress(i*2);
                          System.Threading.Thread.Sleep(100);
                      }
                  }
              }
      

        看for (int i = 0; i <= 50; i++)以及bgWorker1.ReportProgress(i*2); 原因就自己琢磨一下了。

       
      2、把參數傳遞給后臺異步操作,以及在后臺運算過程中實時的把信息在前臺用戶界面UI上顯示出來。
      為方便展示,我們在上面的示例中加入一個名為txtStatus的TextBox。
       
       先來看看MSDN的說法: RunWorkerAsync方法可以接受一個 object 類型的參數。
      使用的方法:
      BtnStart啟動后臺異步操作時讓RunWorkerAsync方法帶一個參數進去。
              private void BtnStart_Click(object sender, EventArgs e)
              {
                  if (!bgWorker1.IsBusy)
                  {
                      int intStart = 1000000;
                      bgWorker1.RunWorkerAsync(intStart);
                  }
              }
      

         DoWork事件通過參數 e 的Argument屬性來獲取傳遞過來的參數。

      private void BgWorker1_DoWork(object sender, DoWorkEventArgs e)
      {
                  int intStart = 0;
                  if (e.Argument != null)
                  {
                      intStart = (int)e.Argument;
                  }
      }
      

        記得傳過來的是個object類型的參數,使用時一定不要忘記了轉換一下。

       
      現在我們把這個傳過來的參數,在后臺DoWork中處理一下,再把處理的實時的結果反饋到用戶界面上來。
      這里要記得:由于DoWork事件內部的代碼運行在非UI線程之上,確保在 DoWork 事件處理程序中不操作任何用戶界面對象。
      所以分兩個地方處理:
              private void BgWorker1_DoWork(object sender, DoWorkEventArgs e)
              {
                  int intStart = 0;
                  if (e.Argument != null)
                  {
                      intStart = (int)e.Argument;
                  }
                  int intSum = intStart;
                  for (int i = 0; i <= 50; i++)
                  {
                      if (bgWorker1.CancellationPending == true)
                      {
                          e.Cancel = true;
                          break; 
                      }
                      else
                      {
                          intSum += i;
                          bgWorker1.ReportProgress(i*2,"循環求和結果:"+intSum.ToString());
                          System.Threading.Thread.Sleep(100);
                      }
                  }
              }
      
              private void BgWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
              {
                  this.pgbPercent.Value = e.ProgressPercentage;
                  this.lblPercent.Text = @"已完成:" + e.ProgressPercentage.ToString() + @"%";
                  this.txtStatus.Text += e.UserState.ToString() + System.Environment.NewLine;
              }
      

        BackgroundWorker的DoWork中ReportProgress加一參數,把需要傳出去的參數通過 bgWorker1.ReportProgress(完成百分比, 傳出參數) 報告出去,ProgressChanged中把這個傳出來的參數顯示到UI上:this.txtStatus.Text += e.UserState.ToString() ...。

       現在運行一下程序試試看。

       

       MSDN上說“由于DoWork事件內部的代碼運行在非UI線程之上,確保在 DoWork 事件處理程序中不操作任何用戶界面對象。而應該通過 ProgressChanged 和 RunWorkerCompleted 事件與用戶界面進行通信。”上面例子也是按MSDN的套路來的,但我個人對這句話的理解是:DoWork不能操作UI,DoWork操作會引發ProgressChanged,ProgressChanged中可以操作UI。那么,我可以在DoWork的外面定義一個變量,從外面傳進去給它作為DoWork初始用,DoWork過程中操作修改它,然后ProgressChanged再把這個變量傳出來,呈現到UI上。
      下面來看看,代碼如下:
       
      using System;
      using System.Collections.Generic;
      using System.ComponentModel;
      using System.Data;
      using System.Drawing;
      using System.Linq;
      using System.Text;
      using System.Threading.Tasks;
      using System.Windows.Forms;
      
      namespace bgwB
      {
          public partial class Form1 : Form
          {
              public Form1()
              {
                  InitializeComponent();
              }
      
              string strBgw = "";
              private void Form1_Load(object sender, EventArgs e)
              {
                  bgWorker1.WorkerReportsProgress = true;
                  bgWorker1.WorkerSupportsCancellation = true;
              }
      
              private void BgWorker1_DoWork(object sender, DoWorkEventArgs e)
              {
                  int intStart = 0;
                  if (e.Argument != null)
                  {
                      intStart = (int)e.Argument;
                  }
                  int intSum = intStart;
                  for (int i = 0; i <= 50; i++)
                  {
                      if (bgWorker1.CancellationPending == true)
                      {
                          e.Cancel = true;
                          break; 
                      }
                      else
                      {
                          strBgw = "times:" + i.ToString() + "  " + DateTime.Now.ToString();
                          intSum += i;
                          bgWorker1.ReportProgress(i*2,"循環求和結果:"+intSum.ToString());
                          System.Threading.Thread.Sleep(100);
      
                      }
                  }
              }
      
              private void BgWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
              {
                  this.pgbPercent.Value = e.ProgressPercentage;
                  this.lblPercent.Text = @"已完成:" + e.ProgressPercentage.ToString() + @"%";
                  this.txtStatus.Text += e.UserState.ToString() + System.Environment.NewLine;
                  this.txtStatus.Text += strBgw + System.Environment.NewLine;
              }
      
              private void BgWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
              {
                  this.lblPercent.Text = "后臺操作結束(可能是程序100%完成,也可能是用戶取消或程序異常導致結束)。";
              }
      
              private void BtnStart_Click(object sender, EventArgs e)
              {            
                  if (!bgWorker1.IsBusy)
                  {
                      this.txtStatus.Text = "";
                      int intStart = 1000000;
                      bgWorker1.RunWorkerAsync(intStart);
                  }
              }
      
              private void BtnCancel_Click(object sender, EventArgs e)
              {
                  bgWorker1.CancelAsync();
              }
          }
      }
      

        結果如圖:

       個人感覺用這個方法傳參數更為靈活。
       

      總結

      至此,BackgroundWorker就基本介紹完了,總的來說,BackgroundWorker用來處理異步處理耗時操作是非常方便快捷的。
       
       
       
       附上這兩個源碼:
       

       

      posted @ 2019-08-16 12:03  Dsw  閱讀(14589)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 无码人妻精品一区二| 四虎av永久在线精品免费观看| 亚洲国产精品美日韩久久| 日本丰满白嫩大屁股ass| 宫西光有码视频中文字幕| 国产精品剧情亚洲二区| 在线播放深夜精品三级| 亚洲色大成网站www在线| 欧美成年性h版影视中文字幕 | 久久精品国产亚洲精品| 人妻中文字幕精品一页| 午夜福利偷拍国语对白| 国产精品综合色区在线观| 人妻系列无码专区69影院| 国产精品大片中文字幕| 国产精品制服丝袜白丝| 久热爱精品视频线路一| 蜜臀av一区二区三区在线| 成人精品区| 无人去码一码二码三码区| 无码日韩av一区二区三区| 国产精品麻豆中文字幕| 日韩中文日韩中文字幕亚| 日本成熟少妇喷浆视频| 人成午夜大片免费视频77777| 最新亚洲春色av无码专区| 国产亚洲一在无在线观看| 亚洲av影院一区二区三区| 成人无码精品免费视频在线观看 | 国产一区二区一卡二卡| 久久天天躁狠狠躁夜夜avapp| 欧洲尺码日本尺码专线美国又| 国产精品久久久久鬼色| 国产精品久久精品国产| 日本精品不卡一二三区| xxxxbbbb欧美残疾人| 久久久欧美国产精品人妻噜噜| 蜜臀午夜一区二区在线播放| 高清欧美性猛交xxxx黑人猛交| 久久精品国产99精品亚洲| 国产成人8X人网站视频|