• 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#中跨线程操作控件

    作者:RonaldHan
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    第5章 语句(1)
    第6章 6.2 创建对象
    js考试题目相关
    第6章 6.3 继承
    第6章 面向对象 导论
    第6章 6.1 理解对象
    第5章 语句(2)
    第6章 面向对象 导论(javascript的面向对象)
    第6章 面向对象深入理解
    第3章 补充(图解JavaScript执行环境、作用域、闭包)
  • 原文地址:https://www.cnblogs.com/ronaldhan/p/3292286.html
Copyright © 2020-2023  润新知