.NET WinForm下一个支持更新ProgressBar进度的DataGridView导出数据到Excel的类

简介:

将DataGridView数据导出到Excel的方法大家应该都不陌生,无非就是对DataGridView进行行和列的遍历,将数据写入到Excel Workbook中,不过项目中需要添加对Excel的COM引用,这个会受到客户端环境的限制。如果直接将数据以CSV的形式导出就更简单了,CSV是一种简单的以分隔符(如逗号,Tab制表符等)分隔数据的文件,支持用Excel或记事本打开。一般而言,直接将数据导出到CSV文件中速度会比较快,但是如果将数据导出到Excel标准格式的文件中时需要调用COM组件中的对象,因此速度会慢一些,这时考虑在UI中加入一个实时进度条是有必要的。如何在多线程中使用ProgressBar相信很多人也都不陌生了,最简单的方法就是使用BackgroundWorker组件,将数据导出的代码放到BackgroundWorker的DoWork事件处理程序中去完成,并实时报告进度,BackgroundWorker的ProgressChanged事件用于更新UI线程中ProgressBar的值,BackgroundWorker的RunWorkerCompleted事件则用来处理操作完成之后的一些事情,例如隐藏ProgressBar,或者显示错误信息等。但是,这里会有一个问题。数据导出的方法一般来说是一个公共方法,它允许在应用程序的不同地方被调用,因此该方法不应该依赖于任何一个窗体或UI元素,我们应该想办法将它独立出来专门写成一个类,同时它还要能支持ProgressBar的更新。

  按照传统的使用BackgroundWorker的方法,我们需要将BackgroundWorker传递到这个类中,同时类里面还需要处理与BackgroundWorker相关的事件,以及与UI相关的一些事情,这显然违背了敏捷开发中的“单一职责原则——一个类只允许有一个引起它变化的原因”。引入太多与UI相关的元素会导致类不够通用,实现起来也很困难。如何从DataGridView导出数据到Excel或CSV文件应该不是什么难事,现在的主要问题是如何支持ProgressBar的进度实时更新。

  一个比较好的办法是采用.NET的事件驱动方式。我们可以在类中定义几个事件,例如开始进行数据导出时的事件,数据正在导出时的事件,数据导出完成之后的事件。调用端通过注册这些事件来取得与类的联系。说白了,联系的纽带就是事件,这个和WinForm程序中各个窗体之间进行互动的原理一样。来看看这些事件的主要用途。

  1. 开始进行数据导出时的事件

  该事件在数据真正开始导出之前被触发,用来获取数据导出总共需要多少步(通常可以认为是DataGridView数据中行和列的总和,试具体导出方式而定)。调用方在事件处理程序中可以更新ProgressBar的属性,如Value,Maximnm,Visible等。

  2. 数据正在导出时的事件

  该事件主要负责更新ProgressBar的进度。我们规定每导出一行或一列数据即触发一次事件。调用方在事件处理程序中更新ProgressBar的进度。

  3. 数据导出完成之后的事件

  在导出数据的方法中,无论什么情况(成功结束或抛出异常)只要结束了数据导出即触发该事件,同时传递一个自定义的继承自EventArgs类的参数。调用方在事件处理程序可以根据这个参数来判断数据导出是否成功完成,从而决定是在UI线程中显示错误信息或给出工程完成的提示信息。

  注意调用方在事件处理程序中必须使用Invoke通过代理来更新UI,否则会抛跨线程UI操作的异常。而对于像MessageBox.Show()这样的模态对话框,如果不是在Invoke中通过代理来调用,它会因为在非UI线程中被执行而失去模态对话框的作用。

  类的完整代码:ExportDataGridViewToExcel.zip

  前端调用的例子:

复制代码
private  ExportDataGridViewToExcel export  =   null ;

public  DetailsTable()
{
    InitializeComponent();

    export 
=   new  ExportDataGridViewToExcel();
    export.DataGridViewControl 
=   this .dataGridView1;
    export.ExportStartingEvent 
+=   new  EventHandler(export_ExportStartingEvent);
    export.ExportProgressingEvent 
+=   new  EventHandler(export_ExportProgressingEvent);
    export.ExportEndedEvent 
+=   new  EventHandler < ExportDataGridViewToExcel.ExportEndedEventArgs > (export_ExportEndedEvent);
}

//  Data export end event.
void  export_ExportEndedEvent( object  sender, ExportDataGridViewToExcel.ExportEndedEventArgs e)
{
    
if  (e.IsCompleted)
    {
        
if  ( this .InvokeRequired)
        {
            
this .Invoke( new  MethodInvoker( delegate ()
            {
                MessageBox.Show(
" Complete! " " Prompt " , MessageBoxButtons.OK, MessageBoxIcon.Information);
            }));
        }
    }
    
else
    {
        
if  ( this .InvokeRequired)
        {
            
this .Invoke( new  MethodInvoker( delegate ()
            {
                MessageBox.Show(
this " Export file failed.\r\n{0} "   +  e.Errors  ==   null   ?   string .Empty : e.Errors.Message,  " Errors " , MessageBoxButtons.OK, MessageBoxIcon.Error);
            }));
        }
    }

    
if  ( this .InvokeRequired)
    {
        
this .Invoke( new  MethodInvoker( delegate ()
        {
            
this .toolStripProgressBar.Visible  =   false ;
        }));
    }
}

//  Data export in process event.
void  export_ExportProgressingEvent( object  sender, EventArgs e)
{
    
int  nowValue  =  Convert.ToInt32(sender);
    
if  ( this .InvokeRequired)
    {
        
this .Invoke( new  MethodInvoker( delegate ()
        {
            
this .toolStripProgressBar.Value  =  nowValue;
        }));
    }
}

//  Data export starting event.
void  export_ExportStartingEvent( object  sender, EventArgs e)
{
    
int  maxValue  =  Convert.ToInt32(sender);
    
if  ( this .InvokeRequired)
    {
        
this .Invoke( new  MethodInvoker( delegate ()
        {
            
this .toolStripProgressBar.Value  =   0 ;
            
this .toolStripProgressBar.Maximum  =  maxValue;
            
this .toolStripProgressBar.Visible  =   true ;
        }));
    }
}

//  Export to CSV.
private   void  exportToCSVToolStripMenuItem_ExportToCSV_Click( object  sender, EventArgs e)
{
    
this .saveFileDialog_CSV.FileName  =   this .Text;
    
if  (saveFileDialog_CSV.ShowDialog()  ==  System.Windows.Forms.DialogResult.OK)
    {
        export.FilePath 
=  saveFileDialog_CSV.FileName;
        Thread thread 
=   new  Thread( new  ParameterizedThreadStart(export.DataGridViewToCSV));
        thread.Start(saveFileDialog_CSV.OpenFile());
    }
}

//  Export to Excel.
private   void  exportToExcelToolStripMenuItem_ExportToExcel_Click( object  sender, EventArgs e)
{
    
this .saveFileDialog_Excel.FileName  =   this .Text;
    
if  (saveFileDialog_Excel.ShowDialog()  ==  System.Windows.Forms.DialogResult.OK)
    {
        export.FilePath 
=  saveFileDialog_Excel.FileName;
        Thread thread 
=   new  Thread( new  ThreadStart(export.DataGridViewToExcel));
        thread.Start();
    }
}

private   void  copyToolStripMenuItem_Copy_Click( object  sender, EventArgs e)
{
    DataObject d 
=   this .dataGridView1.GetClipboardContent();
    Clipboard.SetDataObject(d);
}

private   void  toolStripButton_ToExcel_Click( object  sender, EventArgs e)
{
    
this .exportToExcelToolStripMenuItem_ExportToExcel.PerformClick();
}

private   void  toolStripButton_ToCSV_Click( object  sender, EventArgs e)
{
    
this .exportToCSVToolStripMenuItem_ExportToCSV.PerformClick();
}
复制代码

  最后三个事件处理程序依次是:DataGridView上下文菜单中的Copy事件;DataGridView上下文菜单中Export to Excel事件,可以直接使用exportToExcelToolStripMenuItem工具条按钮的PerformClick方法;DataGridView上下文菜单中的Export to CSV事件,直接使用exportToCSVToolStripMenuItem工具条按钮的PerformClick方法。


本文转自Jaxu博客园博客,原文链接:http://www.cnblogs.com/jaxu/archive/2011/08/03/2126497.html,如需转载请自行联系原作者


相关文章
|
3天前
|
Java 数据安全/隐私保护
Java无模版导出Excel 0基础教程
经常写数据导出到EXCEL,没有模板的情况下使用POI技术。以此作为记录,以后方便使用。 2 工具类 样式工具: 处理工具Java接口 水印工具 导出Excel工具类 3 测试代码 与实际复杂业务不同 在此我们只做模拟 Controller Service 4 导出测试 使用Postman进行接口测试,没接触过Postman的小伙伴可以看我这篇博客Postman导出excel文件保存为文件可以看到导出很成功,包括水印 sheet页名称自适应宽度。还有一些高亮……等功能可以直接搜索使用
Java无模版导出Excel 0基础教程
|
8天前
|
数据格式 Python
Python代码示例,读取excel表格,将行数据转为列数据。(10)
【7月更文挑战第10天】Python代码示例,读取excel表格,将行数据转为列数据。
27 2
|
3天前
|
前端开发
使用Postman导出excel
在本文档中,作者分享了如何使用Postman测试导出Excel接口的两种方法。配以四张图片说明了设置步骤,包括选择接口请求方式、设置Header(Content-Type: multipart/form-data)、Body中选取form-data类型以及指定文件。尽管代码指定了文件名,但在Postman的响应中不会显示,提示需要前端进一步处理。
|
9天前
|
前端开发 JavaScript PHP
技术心得:前端点击按钮,导入excel文件,上传到后台,excel接收和更新数据
技术心得:前端点击按钮,导入excel文件,上传到后台,excel接收和更新数据
10 0
|
10天前
|
数据可视化 数据挖掘 数据处理
Python对Excel两列数据进行运算【从基础到高级的全面指南】
【7月更文挑战第6天】使用Python的`pandas`库处理Excel数据,涉及安装`pandas`和`openpyxl`,读取数据如`df = pd.read_excel(&#39;data.xlsx&#39;)`,进行运算如`df[&#39;Sum&#39;] = df[&#39;Column1&#39;] + df[&#39;Column2&#39;]`,并将结果写回Excel。`pandas`还支持数据筛选、分组、可视化、异常处理和性能优化。通过熟练运用这些功能,可以高效分析Excel表格。
17 0
|
19天前
|
JSON JavaScript 数据格式
vue 电子表格Excel的上传导入、导出下载、读取本地Excel、json转Excel
vue 电子表格Excel的上传导入、导出下载、读取本地Excel、json转Excel
24 0
|
2月前
|
开发框架 前端开发 .NET
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
117 0
|
2月前
|
开发框架 前端开发 JavaScript
JavaScript云LIS系统源码ASP.NET CORE 3.1 MVC + SQLserver + Redis医院实验室信息系统源码 医院云LIS系统源码
实验室信息系统(Laboratory Information System,缩写LIS)是一类用来处理实验室过程信息的软件,云LIS系统围绕临床,云LIS系统将与云HIS系统建立起高度的业务整合,以体现“以病人为中心”的设计理念,优化就诊流程,方便患者就医。
44 0
|
2月前
|
开发框架 前端开发 .NET
C# .NET面试系列六:ASP.NET MVC
<h2>ASP.NET MVC #### 1. MVC 中的 TempData\ViewBag\ViewData 区别? 在ASP.NET MVC中,TempData、ViewBag 和 ViewData 都是用于在控制器和视图之间传递数据的机制,但它们有一些区别。 <b>TempData:</b> 1、生命周期 ```c# TempData 的生命周期是短暂的,数据只在当前请求和下一次请求之间有效。一旦数据被读取,它就会被标记为已读,下一次请求时就会被清除。 ``` 2、用途 ```c# 主要用于在两个动作之间传递数据,例如在一个动作中设置 TempData,然后在重定向到另
177 5
|
2月前
|
开发框架 前端开发 .NET
进入ASP .net mvc的世界
进入ASP .net mvc的世界