zoukankan      html  css  js  c++  java
  • 循序渐进开发WinForm项目(5)--Excel数据的导入导出操作

    随笔背景:在很多时候,很多入门不久的朋友都会问我:我是从其他语言转到C#开发的,有没有一些基础性的资料给我们学习学习呢,你的框架感觉一下太大了,希望有个循序渐进的教程或者视频来学习就好了。

    其实也许我们每天面对的太多东西了,觉得很多都稀松平常了,即使很细微的地方,可能我们都已经形成习惯了。反过来,如果我们切换到其他领域,如IOS、android,那么开始我们可能对里面很多设计的规则不甚了解,开始可能也是一头雾水。

    本篇继续上一篇《循序渐进开发WinForm项目(4)--Winform界面模块的集成使用》,继续介绍如何循序渐进开发Winform项目,介绍业务模块常见的导入导出操作的功能实现,使得我们能够快速,高效开发常见的模块功能。

    上篇随笔我们介绍到自动代码生成的界面如下所示,具备了导入、导出操作,这个操作是针对Excel进行的。

    下面我们来介绍这个在很多模块里面常见的Excel导入、Excel导出操作是如何实现的。

    1、Excel数据的导出操作

    由于我为了演示的目的,我在客户信息表里面只是设计了几个代表性的字段,下面我们来看看代码生成工具自动生成的界面后台代码是如何的。

            /// <summary>
            /// 导出Excel的操作
            /// </summary>
            private void btnExport_Click(object sender, EventArgs e)
            {
                string file = FileDialogHelper.SaveExcel(string.Format("{0}.xls", moduleName));
                if (!string.IsNullOrEmpty(file))
                {
                    string where = GetConditionSql();
                    List<CustomerInfo> list = BLLFactory<Customer>.Instance.Find(where);
                    DataTable dtNew = DataTableHelper.CreateTable("序号|int,姓名,年龄,创建人,创建时间");
                    DataRow dr;
                    int j = 1;
                    for (int i = 0; i < list.Count; i++)
                    {
                        dr = dtNew.NewRow();
                        dr["序号"] = j++;
                         dr["姓名"] = list[i].Name;
                         dr["年龄"] = list[i].Age;
                         dr["创建人"] = list[i].Creator;
                         dr["创建时间"] = list[i].CreateTime;
                         dtNew.Rows.Add(dr);
                    }
    
                    try
                    {
                        string error = "";
                        AsposeExcelTools.DataTableToExcel2(dtNew, file, out error);
                        if (!string.IsNullOrEmpty(error))
                        {
                            MessageDxUtil.ShowError(string.Format("导出Excel出现错误:{0}", error));
                        }
                        else
                        {
                            if (MessageDxUtil.ShowYesNoAndTips("导出成功,是否打开文件?") == System.Windows.Forms.DialogResult.Yes)
                            {
                                System.Diagnostics.Process.Start(file);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        LogTextHelper.Error(ex);
                        MessageDxUtil.ShowError(ex.Message);
                    }
                }
             }

    上面的代码中,FileDialogHelper.SaveExcel 函数是调用公用类库模块,弹出一个选择保存文件的对话框,如果你没有这个类,你可以自己添加代码实现这个操作(这就是公用类库的好处,在使用的时候能够快速调用,减少代码,提高效率)。

    然后根据客户录入的条件检索需要的数据内容:string where = GetConditionSql();

    接着就是构建一个相关字段的表格对象:DataTableHelper.CreateTable,这里面也是使用公用类库来方便创建各种字段的表格,默认字段为字符串格式,如果需要如整形格式的,可以通过|进行分割,如“序号|int” 。

    创建DataTable对象后,我们遍历对象集合,把它里面的数据一行行的赋值给DataRow对象就可以了。

                    for (int i = 0; i < list.Count; i++)
                    {
                        dr = dtNew.NewRow();
                        dr["序号"] = j++;
                         dr["姓名"] = list[i].Name;
                         dr["年龄"] = list[i].Age;
                         dr["创建人"] = list[i].Creator;
                         dr["创建时间"] = list[i].CreateTime;
                         dtNew.Rows.Add(dr);
                    }

    赋值后,就是需要把DataTable对象转换为Excel的操作过程了,这里操作分为两步,第一是创建Excel文档,第二个是写数据的表头和数据行信息,也就是数据的写入操作,这里面我们把它封装在公用类库里面,方便模块之间的调用。

    导出Excel模块采用了基于Aspose.Cell的组件进行数据的写入操作:AsposeExcelTools.DataTableToExcel2

    导出完成后,我们提示用户是否打开Excel文件。

    if (MessageDxUtil.ShowYesNoAndTips("导出成功,是否打开文件?") == System.Windows.Forms.DialogResult.Yes)
    {
            System.Diagnostics.Process.Start(file);
    }

    最终,完成功能后,我们运行程序,导出Excel数据的效果如下所示。

    2、Excel数据的导入操作

    相对于数据的导出操作,Excel数据的导入操作会稍微麻烦一点,你至少需要选择一个文件,文件最好以固定的模板进行导入,因此为了让用户确认数据的有效性,我们最好能提供了一个把Excel数据显示出来再确认导入的过程,这样可以减少导入错误数据的可能。

    我们知道,这种常见的导入操作,很多业务模块可能都需要,因此有必要考虑把它抽象出来,作为一个通用的导入模块,这样我们可以多次利用,非常方便,因此我们提炼这个通用导入的模块特性如下所示。

    Excel数据的导入模块,默认生成界面的时候,也已经一并生成了,我们来看看其中的代码。

            private string moduleName = "客户信息";
            /// <summary>
            /// 导入Excel的操作
            /// </summary>          
            private void btnImport_Click(object sender, EventArgs e)
            {
                string templateFile = string.Format("{0}-模板.xls", moduleName);
                FrmImportExcelData dlg = new FrmImportExcelData();
                dlg.SetTemplate(templateFile, System.IO.Path.Combine(Application.StartupPath, templateFile));
                dlg.OnDataSave += new FrmImportExcelData.SaveDataHandler(ExcelData_OnDataSave);
                dlg.OnRefreshData += new EventHandler(ExcelData_OnRefreshData);
                dlg.ShowDialog();
            }

    其中FrmImportExcelData 是一个界面基础模块中定义的一个通用导入模块,里面实现了一些如显示Excel数据,模板信息关联,保存数据的接口等操作。我们来看看它的程序运行的效果。

    其中我们通过代码 dlg.SetTemplate 指定模板就是用来关联Excel模板信息的,我们让可以尽可能的选择正确的模板进行录入数据。

    用户通过第2的标识,指定要导入的Excel数据文件,选择文件后,数据会自动显示出来方便确认。

    但我们选择保存数据的操作的时候,这个通用模块会执行保存的逻辑代码,并调用由创建者实现的代码逻辑,如上面代码的dlg.OnDataSave就是在执行保存的时候,执行的代码逻辑,我们来看看生成的一些代码实现。

            bool ExcelData_OnDataSave(DataRow dr)
            {
                bool success = false;
                bool converted = false;
                DateTime dtDefault = Convert.ToDateTime("1900-01-01");
                DateTime dt;
                CustomerInfo info = new CustomerInfo();
                info.Name = dr["姓名"].ToString();
                info.Age = dr["年龄"].ToString().ToInt32();
                info.Creator = dr["创建人"].ToString();
                converted = DateTime.TryParse(dr["创建时间"].ToString(), out dt);
                if (converted && dt > dtDefault)
                {
                    info.CreateTime = dt;
                }
      
                success = BLLFactory<Customer>.Instance.Insert(info);
                 return success;
            }

    我们知道,导入的时候,是遍历每行Excel进行数据保存操作的,因此我们这里给出了一个一行的操作代码即可:bool ExcelData_OnDataSave(DataRow dr),里面的逻辑,在数据保存的时候会被模块进行调用。

    上面的操作,是一条条的进行操作,如果累计超过3条记录出错,模块提示是否继续还是退出。

    这里面并没有采用事务的操作,对于一些如Sqlite的大批量的数据操作(速度提升很快),建议采用事务进行处理,关于这个可以参考《Winform开发框架之通用数据导入导出操作的事务性操作完善》进行修改调整。

    最后,我们的Excel数据导入完成后,为了及时更新主界面的数据,我们也定义了一个事件作为回调,如下所示。

    dlg.OnRefreshData += new EventHandler(ExcelData_OnRefreshData);

    这个事件的实现代码就是在主界面的数据绑定更新。

            void ExcelData_OnRefreshData(object sender, EventArgs e)
            {
                BindData();
            }

    循序渐进开发WInform项目--系列文章导引:

    循序渐进开发WinForm项目(5)--Excel数据的导入导出操作

    循序渐进开发WinForm项目(4)--Winform界面模块的集成使用

    循序渐进开发WinForm项目(3)--Winform界面层的项目设计

    循序渐进开发WinForm项目(2)--项目代码的分析

     《循序渐进开发WinForm项目(1) --数据库设计和项目框架的生成

  • 相关阅读:
    UVA 1513
    《ArcGIS Runtime SDK for Android开发笔记》——问题集:.geodatabase创建,创建时内容缺失问题总结
    《ArcGIS Runtime SDK for Android开发笔记》——问题集:使用TextSymbol做标注显示乱码
    《ArcGIS Runtime SDK for Android开发笔记》——(7)、示例代码arcgis-runtime-samples-android的使用
    《ArcGIS Runtime SDK for Android开发笔记》——(6)、基于Android Studio的ArcGIS Android工程结构解析
    《ArcGIS Runtime SDK for Android开发笔记》——(5)、基于Android Studio构建ArcGIS Android开发环境(离线部署)
    《ArcGIS Runtime SDK for Android开发笔记》——(4)、基于Android Studio构建ArcGIS Android开发环境
    《ArcGIS Runtime SDK for Android开发笔记》——(3)、ArcGIS Runtime SDK概述
    《ArcGIS Runtime SDK for Android开发笔记》——(2)、Android Studio基本配置与使用
    《ArcGIS Runtime SDK for Android开发笔记》——(1)、Android Studio下载与安装
  • 原文地址:https://www.cnblogs.com/wuhuacong/p/3579968.html
Copyright © 2011-2022 走看看