.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,如需转载请自行联系原作者


相关文章
|
6月前
|
Python
如何根据Excel某列数据为依据分成一个新的工作表
在处理Excel数据时,我们常需要根据列值将数据分到不同的工作表或文件中。本文通过Python和VBA两种方法实现该操作:使用Python的`pandas`库按年级拆分为多个文件,再通过VBA宏按班级生成新的工作表,帮助高效整理复杂数据。
|
6月前
|
数据采集 数据可视化 数据挖掘
用 Excel+Power Query 做电商数据分析:从 “每天加班整理数据” 到 “一键生成报表” 的配置教程
在电商运营中,数据是增长的关键驱动力。然而,传统的手工数据处理方式效率低下,耗费大量时间且易出错。本文介绍如何利用 Excel 中的 Power Query 工具,自动化完成电商数据的采集、清洗与分析,大幅提升数据处理效率。通过某美妆电商的实战案例,详细拆解从多平台数据整合到可视化报表生成的全流程,帮助电商从业者摆脱繁琐操作,聚焦业务增长,实现数据驱动的高效运营。
|
8月前
|
存储 安全 大数据
网安工程师必看!AiPy解决fscan扫描数据整理难题—多种信息快速分拣+Excel结构化存储方案
作为一名安全测试工程师,分析fscan扫描结果曾是繁琐的手动活:从海量日志中提取开放端口、漏洞信息和主机数据,耗时又易错。但现在,借助AiPy开发的GUI解析工具,只需喝杯奶茶的时间,即可将[PORT]、[SERVICE]、[VULN]、[HOST]等关键信息智能分类,并生成三份清晰的Excel报表。告别手动整理,大幅提升效率!在安全行业,工具党正碾压手动党。掌握AiPy,把时间留给真正的攻防实战!官网链接:https://www.aipyaipy.com,解锁更多用法!
|
6月前
|
Python
Excel中如何批量重命名工作表与将每个工作表导出到单独Excel文件
本文介绍了如何在Excel中使用VBA批量重命名工作表、根据单元格内容修改颜色,以及将工作表导出为独立文件的方法。同时提供了Python实现导出工作表的代码示例,适用于自动化处理Excel文档。
|
6月前
|
Python
将Excel特定某列数据删除
将Excel特定某列数据删除
|
7月前
|
Java 测试技术 数据库
spring号码归属地批量查询,批量查询号码归属地,在线工具,可按省份城市运营商号段分类分开分别导出excel表格
简介:文章探讨Spring Boot项目启动优化策略,通过自定义监听器、异步初始化及分库分表加载优化等手段,将项目启动时间从280秒缩短至159秒,提升约50%,显著提高开发效率。
|
11月前
|
分布式计算 Hadoop 大数据
从Excel到Hadoop:数据规模的进化之路
从Excel到Hadoop:数据规模的进化之路
242 10
|
监控 前端开发 API
一款基于 .NET MVC 框架开发、功能全面的MES系统
一款基于 .NET MVC 框架开发、功能全面的MES系统
392 5
|
开发框架 前端开发 .NET
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
461 0
|
开发框架 前端开发 JavaScript
ASP.NET MVC 教程
ASP.NET 是一个使用 HTML、CSS、JavaScript 和服务器脚本创建网页和网站的开发框架。
248 7

热门文章

最新文章