C#中使用BackgroundWorker完成狀態更新


前段時間項目需要,寫了個操作Excel表格的程序。先介紹背景,合作單位每天有氣井生產數據產生,他們的慣例是將數據存放在一個Excel表格中,通過日期及井口名稱標識記錄的唯一性,為陳述方便,此表稱為總表。由於數據管理的落后,他們已經在總表中存放所有井口(約200口)近3年的生產數據,約有2萬條記錄,每天新增記錄有200條。另外,單位要對每個井口的生產狀況進行分析,他們現在的做法是為井口建立Excel文件,一般一個文件包含10個工作表,每個工作表存放一個井口從生產到當日的生產數據,這些Excel文件稱為單井表。現在的一個工作流程是,手工將總表中每個井口當日生產數據復制到單井表中,一般熟練人員需要兩三個小時才能完成此項單調工作。復制結束后,需要更新單井表中每口井的生產狀態曲線,將當日數據追加上去。程序的目標是,自動化完成數據的復制及生產狀態曲線的更新。

考慮到復制數據和更新曲線圖會耗費一段時間,有必要在界面上對處理進度進行提示,由此選用BackgroundWorker,將耗時的復制、更新操作放入后台進行就變得必須了。

  BackgroundWorker對象有三個主要的事件:

  DoWork - 當BackgroundWorker對象的多線程操作被執行時觸發。

  RunWokerCompleted - 當BackgroundWoker對象的多線程操作完成時觸發。

  ProgressChanged - 當BackgroundWorker對象的多線程操作狀態改變時觸發。

  另外還有一個非常重要的屬性WorkerReportsProgress - 如果想讓BackgroundWorker對象以異步的方式報告線程實時進度,必須將該屬性的值設為true。

  BackgroundWorker對象的ReportProgress方法用於向主線程返回后台線程執行的實時進度。

下面上代碼:

  1         public void DoWork(object sender, DoWorkEventArgs e)
  2         {
  3             // 事件處理,指定處理函數  
  4             e.Result = ProcessProgress(bkWorker, e);
  5         }
  6 
  7         private int ProcessProgress(object sender, DoWorkEventArgs e)
  8         {
  9             //從一個excel表格中復制數據到另外一個表格中
 10             //打開一個工作表,找到日期一欄為當日日期的一行的位置
 11             //找到此工作表中日期為當日日期的最后一條記錄的位置
 12             //循環訪問中間的行,將其copy到對應的工作表中
 13             //循環體中要首先判斷工作表中最后一條記錄的位置
 14             //之后將copy的數據粘貼到其之后一行,保存文檔
 15 
 16             //配置打開文件及存放文件路徑,以后修改為使用xml文件保存參數的形式
 17             //string openFileName = @"D:\ExcelData\各氣井每日生產數據.xls";
 18             //string saveFileName = @"D:\ExcelData\單井每日生產數據.xls";
 19             string openFileName = strAllData;
 20             string saveFileFolder = strSingleData;
 21 
 22             try
 23             {
 24                 //查詢某一列第一次出現某個值所在單元格的位置
 25                 //查詢某一列最后一次出現某個值所在單元格的位置
 26                 Excel.Workbook wb = p_eh.GetWBFromExcel(openFileName);
 27                 Excel.Worksheet ws = (Excel.Worksheet)wb.Worksheets[1];
 28                 string columnStart = "A1";
 29                 //需要查看此處date的格式
 30                 //strDate 2013-07-12格式
 31                 string strDate = DateTime.Now.Date.ToShortDateString();
 32                 strDate = strDate.Replace("-0", "-");
 33                 Excel.Range firstRange = p_eh.FindFirstMatch(ws, columnStart, strDate);
 34                 int rowIndexStart = firstRange.Row;
 35                 Excel.Range lastRange = p_eh.FindLastMatch(ws, columnStart, strDate);
 36                 int rowIndexEnd = lastRange.Row;
 37                 if (rowIndexStart.Equals(rowIndexEnd))
 38                 {
 39                     MessageBox.Show("輸入文件數據有誤");
 40                 }
 41                                
 42                 Excel.Workbook swb = null;
 43                 Excel.Worksheet sws = null;
 44                 string saveFileName;
 45                 for (int i = 0; i <= rowIndexEnd - rowIndexStart; i++)
 46                 {
 47                     //將所在行的數據拷貝到對應的文件worksheet中
 48                     //獲取名稱單元格
 49                     Excel.Range nameRange = ws.get_Range("B" + (i + rowIndexStart).ToString(), Type.Missing);
 50                     string wellName = nameRange.Text.ToString();
 51                     if (wellName != null)
 52                     {
 53                         //根據獲取的名稱,查詢所在的xls文件名稱
 54                         saveFileName = GetSaveFileName(wellName);
 55                         swb = p_eh.GetWBFromExcel(saveFileFolder + "\\" + saveFileName);
 56                         sws = p_eh.GetWSByName(swb, wellName);
 57                         //需要找到當前工作表最后一條記錄所在的位置
 58                         int lastUsedRowIndex = p_eh.GetLastUsedRow(sws, columnStart);
 59                         int lastUsedColumnIndex = p_eh.GetLastUsedColumn(sws, "A5");
 60                         string columnName = p_eh.GetExcelColumnName(lastUsedColumnIndex);
 61                         Excel.Range dataRange = ws.get_Range("A" + (rowIndexStart + i).ToString(), columnName + (rowIndexStart + i).ToString());
 62                         Excel.Range distinationRange = sws.get_Range("A" + (lastUsedRowIndex + int.Parse("1")).ToString(), columnName + (lastUsedRowIndex + int.Parse("1")).ToString());
 63                         //此種復制不能保持原有格式
 64                         //dataRange.Copy(Type.Missing);
 65                         //distinationRange.PasteSpecial(Microsoft.Office.Interop.Excel.XlPasteType.xlPasteValues, Microsoft.Office.Interop.Excel.XlPasteSpecialOperation.xlPasteSpecialOperationNone, false, false);
 66                         //需要保持原有格式
 67                         sws.Cells.Columns.AutoFit();
 68                         dataRange.Copy(distinationRange);
 69                         //Excel.Range dateRange = sws.get_Range("A" + (lastUsedRowIndex + int.Parse("1")).ToString(), Type.Missing);
 70                         //dateRange.Value2 = strDate;
 71                         //dataRange.Cells.Font.Size = 10;
 72                         //dataRange.VerticalAlignment = Excel.XlVAlign.xlVAlignCenter;
 73                         //dataRange.HorizontalAlignment = Excel.XlVAlign.xlVAlignCenter;
 74                         swb.Save();
 75                     }
 76                     // 狀態報告  
 77                     bkWorker.ReportProgress((int)(100*i / (rowIndexEnd - rowIndexStart)));
 78                     // 等待,用於UI刷新界面,很重要  
 79                     System.Threading.Thread.Sleep(1);
 80                 }
 81                 wb.Close(Type.Missing, Type.Missing, Type.Missing);
 82                 swb.Close(Type.Missing, Type.Missing, Type.Missing);
 83                 //此處注銷使用的各種excel對象
 84                 if (ws != null)
 85                 {
 86                     System.Runtime.InteropServices.Marshal.ReleaseComObject(ws);
 87                 }
 88                 if (wb != null)
 89                 {
 90                     System.Runtime.InteropServices.Marshal.ReleaseComObject(wb);
 91                 }
 92                 if (sws != null)
 93                 {
 94                     System.Runtime.InteropServices.Marshal.ReleaseComObject(sws);
 95                 }
 96                 if (swb != null)
 97                 {
 98                     System.Runtime.InteropServices.Marshal.ReleaseComObject(swb);
 99                 }
100             }
101             catch (System.Exception ex)
102             {
103                 p_eh.Dispose();
104             }
105             p_eh.KillAllExcelProcess();
106             return -1;
107         }
108 
109         public void ProgessChanged(object sender, ProgressChangedEventArgs e)
110         {
111             this.progressBar1.Value = e.ProgressPercentage;
112             int percent = e.ProgressPercentage;
113             this.label1.Text = "處理進度:" + Convert.ToString(percent) + "%";
114         }

其他有關BackgroundWorker設置如下:

1 CheckForIllegalCrossThreadCalls = false;
2 bkWorker.WorkerReportsProgress = true;
3 bkWorker.WorkerSupportsCancellation = true;
4 bkWorker.DoWork += new DoWorkEventHandler(DoWork);
5 bkWorker.ProgressChanged += new ProgressChangedEventHandler(ProgessChanged);
6 bkWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(CompleteWork);

以上設置中第一行不檢測跨線程操作,是一種簡單的避免跨線程操作異常的方式,第二行則提示狀態更改。

程序運行界面如下:

這個程序中主要有兩點,一個是BackgroundWorker的用法,另一個是寫了個操作Excel表格的類,完成數據表格和內存中DataTable的互相轉換,Excel表格的各種查詢。

寫這篇文章是因為復習到多線程,想起來要把這點總結下,已經看到一篇寫的不錯的文章,貼下地址:C#多線程總結

另外本文寫作參考鏈接:1.多線程:C#.NET中使用BackgroundWorker在模態對話框中顯示進度條;2.C#中跨線程操作控件


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM