2023年2月

由于我们开发的辅助工具Database2Sharp需要支持多种数据库,虽然我们一般使用SQLServer来开发应用较多,但是Oracle等其他数据库也是常用的数据库之一,因此也是支持使用Oracle等数据库进行代码的快速生成。在此之前我一直要求用户使用代码生成工具的时候,如果使用Oracle开发,则需在开发环境中安装Oracle客户端,以便继续利用微软的System.Data.OracleClient方式访问Oracle,不过这样开发环境就会麻烦一些。另外还带来一个问题,使用这些驱动的时候,由于系统的限制,还会区分32位或者64位的问题,不能实现兼容性的访问。为了彻底解决这个问题,我们使用ODP.NET(Oracle.ManagedDataAccess.dll)访问Oracle数据库,实现免安装Oracle客户端,兼容32位64位Oracle驱动。

1)代码生成工具介绍

Database2Sharp是一款代码生成工具和数据库文档生成工具,该工具从2005年开始至今,一直伴随着我们的客户和粉丝们经历着过各种各样的项目开发,在实际开发中能带来效率的提高及编程的快乐。

Database2Sharp是一款主要用于C#代码生成以及数据库文档生成的工具,软件支持Oracle、SqlServer、MySql、PostgreSQL、Sqlite、Access以及国产达梦等数据库的代码生成,可以生成各种架构代码、生成Winform界面代码、Web界面代码(包括EasyUI和BootstrapWeb界面)、Entity Framework实体框架代码、导出数据库文档、浏览数据库架构、查询数据、生成Sql脚本等,还整合自定义模板和数据库信息的引擎,方便编写自定义模板调试和开发。生成的框架代码支持多种数据库一起使用,也支持不同业务的数据库切割为多个库进行使用,是一种适应性非常强、弹性很好的应用框架。

Database2Sharp推荐采用软件功能“
Enterprise Library
代码生成”
来生成项目代码,这个架构体系生成整个项目工程框架,包含实体类、数据访问类、业务类、Web页面代码、WCF相关服务层(可选)、Web API服务层(可选),以及各种服务的调用包装层代码等。该架构利用泛型及缓存机制,良好的架构极大简化代码,强大完善的基类机制使您甚至不用编写一行代码就能顺利运行。一个简单点击几次鼠标就能完成一周代码量的代码生成工具,效率惊人、友好体贴,真正的开发好伴侣。

当然,开发的过程是一个繁复、精细的过程,因此Database2Sharp也吸收了来自我们自己的实际需求,以及很多同仁朋友的宝贵意见,一直在改进,一直努力做到更好,以求达到一个更加完美、更加易用的境界。

在我们开发软件的时候,解决方案项目基于一定的分层组织,每个项目分层中,各个类的关系也是确定的,借助辅助工具(结合模板引擎)可以快速生成我们所需要的代码,并极大提高我们软件的开发效率,Database2Sharp代码生成工具就是一款专门针对我们自己框架结构配套的开发工具。

Database2Sharp代码生成工具,主要是基于数据库提取的元数据信息,根据表的信息和关系,字段信息等内容,生成我们框架所需要分层的类代码。

对于Winform开发,可以根据Winform框架或者混合框架的窗体界面类,生成标准的界面代码,列表界面默认具有分页查询、导入导出、高级查询、编辑、删除事件绑定,编辑界面则具有获取数据并显示在控件,保存后执行更新或者写入的操作。

对于Web开发,可以根据EasyUI控件界面或者Bootstrap控件界面的不同,生成对应的视图HTML代码和控制器类代码,同时这些界面默认也具有分页查询,导入导出,显示明细和保存数据的功能。

软件主要界面如下所示。

2、代码生成工具中使用ODP.NET(Oracle.ManagedDataAccess.dll)访问Oracle数据库

首先通过Nugget程序包下载一个Oracle.ManagedDataAccess.dll的文件,然后进行使用即可,经过测试使用这个类库,可以无视数据库系统的位数,最重要的是减少了Oracle客户端的安装。

为了和原有的系统支持的OracleClient实现区分,以便继续保留原有方式的处理,那么我们增加一个特别的OracleManaged类实现Oracle元数据的处理即可。

应用这个Oracle.ManagedDataAccess方式,相对于OracleClient方式,我们几乎不用变化任何对象的名称,只是换了一个命名空间而已,基本实现完全兼容。

有了这个获取数据的方式,当然需要对数据配置的界面增加一个OracleManaged的对应方式了,因为Oracle.ManagedDataAccess和OracleClient的连接字符串有所差异的。

前者Oracle.ManagedDataAccess的连接字符串变为:

Data Source=  (DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = orcl.mshome.net)
)
);User ID=win;Password=win

依照这个配置的参数我们修改下Oracle数据库连接字符串的配置界面如下:

其中我们对于Oracle连接字符串描述部分,提示参考PLSQL Developer里面【帮助】【支持信息】 【TNS名称】的对应部分即可,如下所示。

有了这些配置信息,我们就可以不管服务端或者本地的Oracle版本是32位的还是64位的,实现全部兼容,并且如果客户端没有安装Oracle客户端,照样可以访问Oracle服务端的数据的。

运行代码生成工具,可以获得Oracle的数据表等信息,可以在Oracle环境下,无需安装Oracle客户端,顺畅使用代码生成工具进行代码的开发工作了。

在前面随笔《
在代码生成工具Database2Sharp中使用ODP.NET(Oracle.ManagedDataAccess.dll)访问Oracle数据库,实现免安装Oracle客户端,兼容32位64位Oracle驱动
》中介绍了在代码生成工具中使用ODP.NET(Oracle.ManagedDataAccess.dll)访问Oracle数据库,如果我们在框架应用中需要使用这个如何处理了?由于我们开发框架底层主要使用微软企业库(目前用的版本是4.1),如果是使用它官方的Oracle扩展,那么就是使用EntLibContrib.Data.OdpNet(这个企业库扩展类库使用了Oracle.DataAccess.dll),不过这种方式还是受限于32位和64位的问题;假如我们使用ODP.NET(Oracle.ManagedDataAccess.dll)方式,可以使用自己扩展企业库支持即可,类似于我们支持国产数据库--达梦数据库一样的原理,使用Oracle.ManagedDataAccess类库可以避免32位和64位冲突问题,实现统一兼容。

1、扩展支持ODP.NET(Oracle.ManagedDataAccess.dll)访问

为了实现自定义的扩展支持,我们需要对企业库的扩展类库进行处理,类似我们之前编写达梦数据库的自定义扩展类库一样,这方面可以了解下之前的随笔《
基于Enterprise Library的Winform开发框架实现支持国产达梦数据库的扩展操作
》,我们现在增加对ODP.NET(Oracle.ManagedDataAccess.dll)方式的扩展支持。

首先我们创建一个项目,并通过Nugget的方式获得对应的Oracle.ManagedDataAccess.dll类库,参考企业库对于Mysql的扩展或者其他的扩展,稍作调整即可。

OracleDatabase类似下面代码

usingSystem;usingSystem.Data;usingSystem.Data.Common;usingMicrosoft.Practices.EnterpriseLibrary.Common;usingMicrosoft.Practices.EnterpriseLibrary.Data;usingMicrosoft.Practices.EnterpriseLibrary.Data.Configuration;usingOracle.ManagedDataAccess.Client;namespaceEntLibContrib.Data.OracleManaged
{
/// <summary> /// <para>Oracle数据库对象(使用ODP驱动)</para> /// </summary> /// <remarks> /// <para> ///Internally uses OracleProvider from Oracle to connect to the database./// </para> /// </remarks> [DatabaseAssembler(typeof(OracleDatabaseAssembler))]public classOracleDatabase : Database
{
/// <summary> ///Initializes a new instance of the<see cref="OracleDatabase"/>class///with a connection string./// </summary> /// <param name="connectionString">The connection string.</param> public OracleDatabase(string connectionString) : base(connectionString, OracleClientFactory.Instance)
{
}
/// <summary> /// <para> ///Gets the parameter token used to delimit parameters for the///Oracle database.</para> /// </summary> /// <value> /// <para>The '?' symbol.</para> /// </value> protected charParameterToken
{
get{return ':';
}
}

.........

主要就是把对应的类型修改为Oracle的即可,如Oracle的名称,以及参数的符号为 :等地方,其他的一一调整即可,不在赘述。

完成后,修改程序集名称,编译为 EntLibContrib.Data.OracleManaged.dll 即可。

2、框架应用的数据库配置项设置

完成上面的步骤,我们就可以在配置文件中增加配置信息如下所示,它就能正常的解析并处理了。

上面使用了两种方式,一种是官方扩展的EntLibContrib.Data.OdpNet方式,一种是我们这里刚刚出炉的 EntLibContrib.Data.OracleManaged方式,完整的数据库支持文件信息如下所示。

<?xml version="1.0"?>
<configuration>
  <configSections>
    <sectionname="dataConfiguration"type="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.DatabaseSettings, Microsoft.Practices.EnterpriseLibrary.Data"/>
    <sectionname="oracleConnectionSettings"type="EntLibContrib.Data.OdpNet.Configuration.OracleConnectionSettings, EntLibContrib.Data.OdpNet" />
  </configSections>
  <connectionStrings>
    <!--SQLServer数据库的连接字符串-->
    <addname="sqlserver"providerName="System.Data.SqlClient"connectionString="Persist Security Info=False;Data Source=(local);Initial Catalog=WinFramework;Integrated Security=SSPI"/>
    
    <!--Oracle数据库的连接字符串-->
    <addname="oracle"providerName="System.Data.OracleClient"connectionString="Data Source=orcl;User ID=whc;Password=whc"/>
    
    <!--MySQL数据库的连接字符串-->
    <addname="mysql"providerName="MySql.Data.MySqlClient"connectionString="Server=localhost;Database=WinFramework;Uid=root;Pwd=123456;"/>
    
    <!--PostgreSQL数据库的连接字符串-->
    <addname="npgsql"providerName="Npgsql"connectionString="Server=localhost;Port=5432;Database=postgres;User Id=postgres;Password=123456"/>
    
    <!--路径符号|DataDirectory|代表当前运行目录-->    
    <!--SQLite数据库的连接字符串-->
    <addname="sqlite"providerName="System.Data.SQLite"connectionString="Data Source=|DataDirectory|\WinFramework.db;Version=3;" />
    <!--Microsoft Access数据库的连接字符串-->
    <addname="access"providerName="System.Data.OleDb"connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|\WinFramework.mdb;User ID=Admin;Jet OLEDB:Database Password=;" />   
    
    <!--IBM DB2数据库的连接字符串-->
    <addname="db2"providerName="IBM.Data.DB2"connectionString="database=whc;uid=whc;pwd=123456"/>
    
    <!--采用OdpNet方式的Oracle数据库的连接字符串-->
    <addname="oracle2"providerName="Oracle.DataAccess.Client"connectionString="Data Source=orcl;User id=win;Password=win;" />
    <addname="oracle3"providerName="OracleManaged"connectionString="Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=orcl.mshome.net)));User ID=win;Password=win" />
  </connectionStrings>
  <dataConfigurationdefaultDatabase="oracle3">
    <providerMappings>
      <adddatabaseType="EntLibContrib.Data.MySql.MySqlDatabase, EntLibContrib.Data.MySql"name="MySql.Data.MySqlClient" />
      <adddatabaseType="EntLibContrib.Data.SQLite.SQLiteDatabase, EntLibContrib.Data.SqLite"name="System.Data.SQLite" />
      <adddatabaseType="EntLibContrib.Data.PostgreSql.NpgsqlDatabase, EntLibContrib.Data.PostgreSql"name="Npgsql" />      
      <adddatabaseType="EntLibContrib.Data.DB2.DB2Database, EntLibContrib.Data.DB2"name="IBM.Data.DB2" />
      <adddatabaseType="EntLibContrib.Data.OdpNet.OracleDatabase, EntLibContrib.Data.OdpNet"name="Oracle.DataAccess.Client" />
      <adddatabaseType="EntLibContrib.Data.Dm.DmDatabase, EntLibContrib.Data.Dm"name="Dm" />
      <!--增加ODP.NET(Oracle.ManagedDataAccess.dll)方式的扩展支持-->
      <adddatabaseType="EntLibContrib.Data.OracleManaged.OracleDatabase, EntLibContrib.Data.OracleManaged"name="OracleManaged" />
    </providerMappings>
  </dataConfiguration>
  
  <appSettings>

  </appSettings>
  <startupuseLegacyV2RuntimeActivationPolicy="true">
    <supportedRuntimeversion="v4.0"sku=".NETFramework,Version=v4.0"/>
    <supportedRuntimeversion="v2.0.50727"/>
  </startup>
</configuration>

这样我们底层就可以实现多种数据库的兼容访问了。

采用不同的数据库,我们需要为不同数据库的访问层进行生成处理,如为SQLServer数据的表生成相关的数据访问层DALSQL,里面放置各个表对象的内容,不过由于采用了相关的继承类处理和基于数据库的代码生成,需要调整的代码很少。

我们来编写一段简单的程序代码来测试支持这种ODP.net方式,测试代码如下所示。

private void btnGetData_Click(objectsender, EventArgs e)
{
string sql = "select * from T_Customer";//+ " Where Name = :name"; Database db =DatabaseFactory.CreateDatabase();
DbCommand command
=db.GetSqlStringCommand(sql);//command.Parameters.Add(new OracleParameter("name", "张三")); using (var ds =db.ExecuteDataSet(command))
{
this.dataGridView1.DataSource = ds.Tables[0];
}
}

测试界面效果如下所示。

以上这些处理,可以适用于Web框架、Bootstrap开发框架、Winform开发框架、混合式开发框架中的应用,也就是CS、BS都可以使用。

在我们基于微信开发框架各种微信项目的时候,往往一个场景一个菜单集合,多个微信项目就可能存在多个不同的菜单组合。由于微信菜单的数量限制,我们想测试一下其他不同项目的菜单功能的时候,如果没有一个很好的管理方案,就会显得很麻烦,本篇随笔介绍如何在管理微信菜单的基础上增加一个菜单组的概念,以便随时激活某个项目的菜单集合,提交到服务器上进行项目切换或者功能测试。

1、项目菜单的处理

一般来说,我们受限于微信菜单的数量限制,微信菜单不能超过三个大菜单,每个大菜单下最多可以延伸五个子菜单,那么一般我们可以在微信应用中管理这些菜单,方便提交到微信服务器上,如下是对菜单树列表的管理。

以及我们对每个菜单进行详细列表信息的管理,包括新增,修改、删除、查询等等的维护。

维护单个菜单的时候,编辑界面如下所示。

如果我们没有引入菜单分组,那么我们只有对部分菜单进行禁用或者删除的处理,一旦在里面整合了多个项目的菜单,数量就不少,就会更加难以管理了。

我们希望保留多个项目的菜单以供参考或者功能测试,那么我们就需要引入一个菜单分组的概念,以便更好的管理这些微信应用菜单。

2、引入菜单分组的菜单管理界面

首先我们在管理的入口先维护菜单的分组,菜单分组其实也是一个菜单记录,只是作为一个顶端的菜单记录存在,方便维护而已。

菜单分组可以禁用、启用,新增、编辑,以及展示该分组下的树形列表和提交到微信服务器上的功能,如下所示是我们对菜单分组的界面设计。

这个是作为一级菜单组的管理界面,以便给我们一个直观的菜单集合的树列表,如果我们需要详细维护菜单的数据,我们可以引导用户进入一个菜单维护的界面,如下所示。

这样我们就有一个对菜单群进行统一维护的菜单分组,也方便我们随时启用某个菜单组群,以便对某个应用进行简单的测试或者体验,特别在我们微信框架整合了多个项目,以便客户切换不同项目进行使用,就显得更加方便。某个时候,随时提交一下就可以及时进行测试,不需要的时候,再更换一个不同的应用菜单群组。

多个项目之间随时提交切换,非常方便。

以上就是关于菜单分组的管理心得,希望对大家有所启发。

之前我在随笔《
使用FastReport报表工具生成报表PDF文档
》介绍过使用FastReport.Net来根据报表模板进行生成PDF,以及随笔《
使用FastReport报表工具生成标签打印文档
》介绍过生成标签文档的处理,基本上都是基于模板进行生成PDF的做法,由于PDF在手机端显示总是觉得不那么方便,不管使用pdfjs或者直接打开PDF,都不太令客户满意,客户希望直接展示图片的方式显示。本篇随笔介绍如何使用FastReport.Net来直接生成报表格式的图片文件。

1、报表模板及数据绑定处理

FastReport.Net是一款适用于Windows Forms, ASP.NET和MVC框架的功能齐全的报表分析解决方案。之前使用直接生成PDF的方式构建报表文档,如下效果所示。

在FastReport设计报表模式里面,我们可以对报表进行设置,以便于在实际运行环境的情况下生成上面的报表文档。在FastReport设计器里面的效果如下所示。

这个报表包含了主表信息,和明细表的信息,我们主表动态信息,可以通过参数的绑定方式绑定,明细表则通过绑定DataTable的方式动态处理即可。

采用参数绑定,我们需要在报表设计器里面定义好我们需要的参数,如下所示。

我们一般预先定义好相关的参数,然后绑定在模板里面,并设置好内容的对其格式即可。

如报表页面里面,我们放置了一个表格,定义好表格的行列和宽度后,双击表格单元格,就可以设置表格单元格的文本内容为对应的参数了,如下界面所示。

对于动态展示的明细列表部分,我们需要定义一个数据源的方式,从而可以让报表模板绑定对应的字段名称。

我根据数据表的信息,生成一个用于绑定明细列表的数据源,如下所示。

这样我们在代码绑定的时候,只需要指定Detail的名称和对应的字段名称即可,有了这些定义,我们可以在报表设计中使用字段绑定了。

对于运行时刻报表数据的绑定,主要使用对应的对象的注册数据和设置参数处理函数即可实现。

//刷新数据源
report.RegisterData(dt, "Detail");foreach (string key indict.Keys)
{
report.SetParameterValue(key, dict[key]);
}
//运行报表 report.Prepare();//导出PDF报表 PDFExport export = newPDFExport();
report.Export(export, realPath);
report.Dispose();

2、实现报表生成图片文档

图片生成的处理,和PDF格式的处理大同小异,主要就是先处理数据的绑定和准备,后续在根据对应的文件后缀名进行相应的图片生成,PDF生成使用PDFExport,图片生成采用的是ImageExport类处理。

如果是基于Web开发的,我们在控制器上处理对应的报表输出文件名称和路径,如下所示。

//导出PDF的文件路径
string exportPdfPath = string.Format("/GenerateFiles/Pres/Report_{0}.jpg", id);//转换为物理路径
string realPath = Server.MapPath(exportPdfPath);

加载报表模板并初始化,这个不管PDF或者换图片格式,处理一样。

//以报表模板,初始化报表对象
Report report = newReport();
report.Load(reportPath);

BS下生成并输出图片文件如下所示

//刷新数据源
report.RegisterData(dt, "Detail");foreach (string key indict.Keys)
{
report.SetParameterValue(key, dict[key]);
}
//运行报表 report.Prepare();//导出PDF报表//PDFExport export = new PDFExport();//导出JPG报表 ImageExport export = newImageExport();//export.JpegQuality = 392;//export.ResolutionY = 226; report.Export(export, realPath);
report.Dispose();

result
= Content(exportPdfPath);//返回Web相对路径

我们看到,图片生成的操作和PDF的处理差不多。

最后生成图片的界面效果如下所示。

如果报表的页数超过一页,我们可以通过参数来生成不同的图片,如下所示。

new ImageExport() { PageRange = PageRange.Current, CurPage = count }

我们来看看另外一个处理代码,如下所示。

//多个图片导出
int count = 1;string firstFileName = exportImgPath.Replace(".png", "");foreach (PageBase item inreport.Pages)
{
string fileName = string.Format("{0}_{1}.png", firstFileName, count);
exportImgPath
=fileName;
report.Export(
new ImageExport() { PageRange = PageRange.Current, CurPage =count }, fileName);
count
++;
}

和之前的不同,这个图片格式指定为PNG,另外可以支持多个页面的图片生成。

针对FastReport报表的特性,我在综合案例里面编写了一个专门用来处理FastREport的案例代码,如下所示。

在较早期的报表套打的时候,我倾向于使用LODOP的ActiveX进行报表的打印或者套打,BS效果还是很不错的。之前利用它在Winform程序里面实现信封套打功能,详细参考《
基于信封套打以及批量打印的实现过程
》,虽然功能能够完美实现,不过由于还需要附带一个不是百分百整合一起的插件,还是有点另类的,虽然只是第一次使用的时候,需要安装一次插件即可。本篇随笔介绍一下如何旧瓶装新酒,使用FastReport报表工具来实现信封的套打及批量打印的功能。

1、信封套打及批量打印功能的回顾

首先我们要有一些特制的信封或者普通信封,这样才能基于这个基础上进行套打,把邮政编码、地址和联系人等信息打印上去。

然后你需要有一个打印设备,我这里采用了一个佳能的喷墨打印机(当然其他的也没问题)。

其次我们开发一个工具来快速实现数据的导入和批量打印,如下界面所示。

最后当然能够满足要求的打印大量的信封出来,减少我们人工干预的麻烦了。

2、使用FastReport报表工具来实现信封的套打及批量打印

首先我们模仿上面的工具界面来做一个新的Winform程序,这次使用DevExpress界面来做,得到界面如下所示。

功能和前面软件的基本一样,只是界面有所变化差异而已。

现在我们来聊聊如何FastReport报表工具来实现套打的处理,这样我们就可以使用它来进行信封的打印了。

首先,和前面随笔《
使用FastReport报表工具生成报表PDF文档
》/《
使用FastReport报表工具生成标签打印文档
》等文章介绍的一样,我们套打一样需要准备好一个报表模板,然后基于这个基础上进行套打处理。

套打的原理,就是预设一个图片和报表的大小,以及放置一些需要打印的内容,预设的图片一般不需要打印出来,这样其他内容打印在特定的纸张上就实现了证书、信封、发票、快递单等的打印了。

而使用FastReport报表工具,我们可以对报表模板里面的元素的位置、大小、样式等进行一定的调整,以适应我们具体的报表需要,基于这个模式我们先设计一个FastReport报表模板,如下所示。

以上模板的设置,主要就是注意定义好几个参数,并将参数和具体的展示控件进行绑定,并加入一个图片作为不打印的元素即可。

报表在运行时刻可以进行模板的调整,如下是报表的【打印设计】界面。

我们可以利用FastReport提供的报表设计工具进行元素位置、大小、样式等方面的调整。这样就可以给客户很大的灵活性进行处理。

报表打印的操作如下代码所示。

        /// <summary>
        ///报表打印测试/// </summary>
        private void btnPrintTest_Click(objectsender, EventArgs e)
{
if(this.txtAddress.Text.Length == 0)
{
MessageDxUtil.ShowTips(
"请输入地址");this.txtAddress.Focus();return;
}
else if (this.txtReceiver.Text.Length == 0)
{
MessageDxUtil.ShowTips(
"请输入收件人");this.txtReceiver.Focus();return;
}

FrmReportPreview dlg
= newFrmReportPreview();var report =dlg.Report;//加载报表 var reportFile = Path.Combine(baseDir, "Report/信封报表.frx");
report.Load(reportFile);
//绑定数据源//定义参数和数据格式 var dict = new Dictionary<string, object>();var zipCode = txtPostCode.Text.Trim().PadRight(6, ' ').ToCharArray();
dict.Add(
"C1", zipCode[0]);
dict.Add(
"C2", zipCode[1]);
dict.Add(
"C3", zipCode[2]);
dict.Add(
"C4", zipCode[3]);
dict.Add(
"C5", zipCode[4]);
dict.Add(
"C6", zipCode[5]);
dict.Add(
"Address", this.txtAddress.Text.Trim());var Recipient = this.txtReceiver.Text.Trim();if(!Recipient.EndsWith(""))
{
Recipient
+= "";
}
dict.Add(
"Recipient", Recipient);//刷新数据源 foreach (string key indict.Keys)
{
report.SetParameterValue(key, dict[key]);
}

dlg.ShowDialog();
}

以上打印处理的时候,会调用打印预览界面展示数据,如下界面所示。

报表打印设计处理,和打印测试差不多,也需要绑定数据,方便预览,代码如下所示。

        /// <summary>
        ///报表打印设计/// </summary>
        private void btnPrintDesign_Click(objectsender, EventArgs e)
{
FrmReportDesign dlg
= newFrmReportDesign();var report =dlg.Report;//加载报表文件 var reportFile = Path.Combine(baseDir, "Report/信封报表.frx");
report.Load(reportFile);
//绑定数据源//定义参数和数据格式 var dict = new Dictionary<string, object>();var zipCode = txtPostCode.Text.Trim().PadRight(6, ' ').ToCharArray();
dict.Add(
"C1", zipCode[0]);
dict.Add(
"C2", zipCode[1]);
dict.Add(
"C3", zipCode[2]);
dict.Add(
"C4", zipCode[3]);
dict.Add(
"C5", zipCode[4]);
dict.Add(
"C6", zipCode[5]);
dict.Add(
"Address", this.txtAddress.Text.Trim());var Recipient = this.txtReceiver.Text.Trim();if (!Recipient.EndsWith(""))
{
Recipient
+= "";
}
dict.Add(
"Recipient", Recipient);//刷新数据源 foreach (string key indict.Keys)
{
report.SetParameterValue(key, dict[key]);
}

dlg.ShowDialog();
}

信封打印,我们不需要一个个确认打印对话框,指定那个PrintDialog为False即可。信封的批量打印代码如下所示。

        /// <summary>
        ///信封批量打印操作/// </summary>
        private void btnBatchPrint_Click(objectsender, EventArgs e)
{
if(dtImport == null || dtImport.Rows.Count == 0)
{
MessageDxUtil.ShowTips(
"没有打印数据");return;
}

FastReport.Report report
= newFastReport.Report();
FastReport.Utils.Res.LocaleFolder
= Path.Combine(baseDir, "L18N");var file = FastReport.Utils.Res.LocaleFolder + @"Chinese (Simplified).frl";
FastReport.Utils.Res.LoadLocale(file);
//加载报表 var reportFile = Path.Combine(baseDir, "Report/信封报表.frx");
report.Load(reportFile);

SplashScreenHelper.Show(
typeof(FrmWaitForm));
SplashScreenHelper.SetCaption(
"正在打印...");int total =dtImport.Rows.Count;int i = 0;foreach(DataRow dr indtImport.Rows)
{
SplashScreenHelper.SetDescription(
string.Format("正在打印...任务 {0} / {1}", i++, total));//绑定数据源//定义参数和数据格式 var dict = new Dictionary<string, object>();var zipCode = dr["邮编"].ToString().Trim().PadRight(6, ' ').ToCharArray();
dict.Add(
"C1", zipCode[0]);
dict.Add(
"C2", zipCode[1]);
dict.Add(
"C3", zipCode[2]);
dict.Add(
"C4", zipCode[3]);
dict.Add(
"C5", zipCode[4]);
dict.Add(
"C6", zipCode[5]);
dict.Add(
"Address", dr["地址"].ToString().Trim());var Recipient = dr["收件人"].ToString().Trim();if (!Recipient.EndsWith(""))
{
Recipient
+= "";
}
dict.Add(
"Recipient", Recipient);//刷新数据源 foreach (string key indict.Keys)
{
report.SetParameterValue(key, dict[key]);
}

report.PrintSettings.ShowDialog
= false;
report.Print();

Thread.Sleep(
100);
}
SplashScreenHelper.SetCaption(
"打印完成!");
SplashScreenHelper.SetDescription(
string.Format("完成全部打印,共打印【{0}】份!", total));
Thread.Sleep(
500);
SplashScreenHelper.Close();
}

我们使用该批量模式测试打印几个信封,效果如下所示。

如果导入数据很多,那么一样和前面的软件打印效果一样,中间不需要人工接入,喝茶等着完成即可。

这个就是整合了FastReport报表工具实现信封套打功能的软件,这样整合后,软件体验性就更加完美了。