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


相关文章
|
8月前
|
Python
如何根据Excel某列数据为依据分成一个新的工作表
在处理Excel数据时,我们常需要根据列值将数据分到不同的工作表或文件中。本文通过Python和VBA两种方法实现该操作:使用Python的`pandas`库按年级拆分为多个文件,再通过VBA宏按班级生成新的工作表,帮助高效整理复杂数据。
|
8月前
|
数据采集 数据可视化 数据挖掘
用 Excel+Power Query 做电商数据分析:从 “每天加班整理数据” 到 “一键生成报表” 的配置教程
在电商运营中,数据是增长的关键驱动力。然而,传统的手工数据处理方式效率低下,耗费大量时间且易出错。本文介绍如何利用 Excel 中的 Power Query 工具,自动化完成电商数据的采集、清洗与分析,大幅提升数据处理效率。通过某美妆电商的实战案例,详细拆解从多平台数据整合到可视化报表生成的全流程,帮助电商从业者摆脱繁琐操作,聚焦业务增长,实现数据驱动的高效运营。
|
10月前
|
存储 安全 大数据
网安工程师必看!AiPy解决fscan扫描数据整理难题—多种信息快速分拣+Excel结构化存储方案
作为一名安全测试工程师,分析fscan扫描结果曾是繁琐的手动活:从海量日志中提取开放端口、漏洞信息和主机数据,耗时又易错。但现在,借助AiPy开发的GUI解析工具,只需喝杯奶茶的时间,即可将[PORT]、[SERVICE]、[VULN]、[HOST]等关键信息智能分类,并生成三份清晰的Excel报表。告别手动整理,大幅提升效率!在安全行业,工具党正碾压手动党。掌握AiPy,把时间留给真正的攻防实战!官网链接:https://www.aipyaipy.com,解锁更多用法!
|
数据采集 数据可视化 数据挖掘
利用Python自动化处理Excel数据:从基础到进阶####
本文旨在为读者提供一个全面的指南,通过Python编程语言实现Excel数据的自动化处理。无论你是初学者还是有经验的开发者,本文都将帮助你掌握Pandas和openpyxl这两个强大的库,从而提升数据处理的效率和准确性。我们将从环境设置开始,逐步深入到数据读取、清洗、分析和可视化等各个环节,最终实现一个实际的自动化项目案例。 ####
2386 10
|
8月前
|
Python
将Excel特定某列数据删除
将Excel特定某列数据删除
|
分布式计算 Hadoop 大数据
从Excel到Hadoop:数据规模的进化之路
从Excel到Hadoop:数据规模的进化之路
305 10
|
数据处理 项目管理
进度一目了然,Excel和看板的神仙联动
在项目管理中,Excel擅长结构化信息记录,但直观展示项目进度稍显不足。结合板.栗.看.板.工具,可将Excel数据同步为任务卡片,清晰显示任务状态、完成时间、负责人和优先级,实现数据与看板的双向联动,提升团队协作效率。
进度一目了然,Excel和看板的神仙联动
|
网络协议 C#
基于.NET WinForm开发的一款硬件及协议通讯工具
基于.NET WinForm开发的一款硬件及协议通讯工具
191 7
|
存储 Java easyexcel
招行面试:100万级别数据的Excel,如何秒级导入到数据库?
本文由40岁老架构师尼恩撰写,分享了应对招商银行Java后端面试绝命12题的经验。文章详细介绍了如何通过系统化准备,在面试中展示强大的技术实力。针对百万级数据的Excel导入难题,尼恩推荐使用阿里巴巴开源的EasyExcel框架,并结合高性能分片读取、Disruptor队列缓冲和高并发批量写入的架构方案,实现高效的数据处理。此外,文章还提供了完整的代码示例和配置说明,帮助读者快速掌握相关技能。建议读者参考《尼恩Java面试宝典PDF》进行系统化刷题,提升面试竞争力。关注公众号【技术自由圈】可获取更多技术资源和指导。
|
前端开发 Android开发
WinForm 直接运行 Admin.NET
本文介绍了如何将 Admin.NET 以 WinForm 桌面程序模式运行,简化了手动配置 Web 服务的过程,便于演示和作为单机软件使用。通过添加特定 NuGet 包、修改 `Program.cs` 和 `Form1.cs` 文件,并调整项目配置,最终实现了在 WinForm 中嵌入 WebView 组件显示 Admin.NET 界面的效果。
234 0
WinForm 直接运行 Admin.NET