此片博文是在你有一定水晶报表基础的前提下参阅的;如果对于水晶报表的基础知识比较薄弱建议先去了解下水晶报表;
因为项目需要,研究了下水晶报表。说实在,这个组件很强大,但是用起来也很麻烦。刚开始使用遇到了老多问题。然后上了搜索引擎搜索。但是我发现,有一个很痛疼的问题。那就是现在搜索引擎搜索到的东西都是COPY的。大家到处复制别人的答案,却连测试都不测试就贴上了,然后一搜索出来的都是千篇一律的东西。要找到正确的解决方案真的是一件很痛苦的事。我不知道你们有没有这样的经理。反正我经常是这样。所以也萌生了自己写帖子的想法。把自己遇到的问题的解决方案写出来。但是因为水平有限,所以可能也会存在很多问题。希望大家多多谅解。多多提出;
好了 进入今天的主题。所谓通用报表,我们来模拟一个需求:现在需要做个报表。这个报表要实现的功能是。配置一个配置文件,配置好要显示的数据表,和数据字段,配置好每个字段在报表中的显示宽度,配置好报表数据要按那个字段的什么排序方式排序;这样,我就只需要一个报表就能显示不同的表的数据,并且可以根据字段数据的长度设置报表中列的宽度;其实这里的通用也是有点牵强的。为什么牵强看下面的解决方案就知道了。
解决方案:通用报表是一个很强大的组件。所以其实很多东西都是我们还为挖掘的。那么通用报表怎么实现呢。我的想法是。先在报表上放一堆公式字段,或者文本对象。然后通过代码,设置每个公式字段(报表的列)的宽度和左边偏移量;而要按照配置文件的需求则可以获取配置文件的条件,然后组合成为sql语句。获取数据填充到一个dataset中。在将这个dataset作为报表的数据源;就可以实现了;
第一步:
假设我的报表最多有10列;那么我需要创建一个DataSet.xsd文件。然后创建一张表;
问题:为什么一定要创建这个文件,代码中创建一个DataSet可不可以?
水晶报表在初始化的时候,需要关联已个数据源,这个数据源哪怕没有数据也没关系,关联数据源有两种方式。一是直接和数据库的表关联,二就是像我们这样创建一个DataSet.xsd文件,然后与这个DataSet.xsd文件关联;
如果没有用任何一种关联的话,会提示:
该报表不包含表。
说明: 执行当前 Web 请求期间,出现未处理的异常。请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息。
异常详细信息: CrystalDecisions.CrystalReports.Engine.DataSourceException: 该报表不包含表。
所以如果不创建创建DataSet文件,而是代码中创建一个DataSet,那么就没有关联数据源,会报如上错误;
接着讲:新增项创建一个DataSet.xsd后,右键新增一张表:然后在表上右键新增列,完事后如下
然后与报表关联:
第二步:创建水晶报表;然后右键公式字段,新增公式字段。然后把公式字段放到报表上,最后结果如下。
然后右键每个公式字段,选择设置对象个数,修改里面的对象名称,这里的对象名称是代码要使用的。建议设置成如:colu1,colu2....colu10 这样在代码中可以用循环来找到每个公式字段!
这里的公式字段我是为每个设置类单线边框,样式可能不是很好看。你也可以自己画线。这个下面的字报表会讲到;
第三步:创建页面,然后在页面上拉个水晶报表的控件
创建完后 有人可能不想要左边的这个组树。水晶报表的版本不一样。可能设置也不一样。我这个是10的。设置方式是将下面的属性改为none;
水晶报表的工具栏很多也是可以去掉的,然后在右上角会有个微标,点击会跳到该组件的官网,可以通过设置属性:
接着是创建配置文件
<?xml version="1.0" encoding="utf-8" ?> <ConfigManage> <Config ID="1"> <TableName Title="系统日志报表">SYS_Log</TableName> <OrderBy Order="desc">logid</OrderBy> <Fields> <Field ChinesName="编号" IsShow="true" Width="1800">logid</Field> <Field ChinesName="日志类别" IsShow="true" Width="1800">logtype</Field> <Field ChinesName="用户编号" IsShow="true" Width="1800">userid</Field> <Field ChinesName="日志内容" IsShow="true" Width="1800">logcontent</Field> <Field ChinesName="操作用户名" IsShow="true" Width="1800">username</Field> <Field ChinesName="操作用户名" IsShow="true" Width="1800">username</Field> </Fields> </Config> </ConfigManage>
然后就是为报表设置数据源和控制列宽的代码了。
/// <summary> /// 获取配置文件的配置信息配置报表 /// </summary> public void GetData() { string Path = ""; string reportPath = ""; string tablename = "";//表名称 string OrderKey = "";//排序的字段 string Order = "";//按什么排序 string title = "";//报表标题 bool Separate = true;//显示页是分页还是连接 string serch = "";//筛选条件 Path = Server.MapPath("Config/ReportConfig.xml"); reportPath = Server.MapPath("CrystalReport3.rpt"); #region 获取配置文件的信息 XmlDocument document = new XmlDocument(); document.Load(Path); XmlNodeList NodeList = document.GetElementsByTagName("TableName"); if (NodeList != null && NodeList.Count > 0) { tablename = NodeList[0].InnerText; title = NodeList[0].Attributes["Title"].Value; } else { return; } NodeList = document.GetElementsByTagName("OrderBy"); if (NodeList != null && NodeList.Count > 0) { OrderKey = NodeList[0].InnerText; Order = NodeList[0].Attributes["Order"].Value; } else { return; } NodeList = document.GetElementsByTagName("Field"); string fields = ""; if (NodeList != null && NodeList.Count > 0) { foreach (XmlNode node in NodeList) { if (node.InnerText != "") { fields += node.InnerText + ","; } } } else { return; } #endregion if (fields.Length > 0) { fields = fields.Substring(0, fields.Length - 1); string sql = "select " + fields + " from " + tablename + " " + serch + " order by " + OrderKey + " " + Order; DataSet ds = new Maticsoft.BLL.CommonClass().Query(sql); if (ds != null && ds.Tables.Count > 0 && ds.Tables[0].Rows.Count > 0) { ReportDocument myReport = new ReportDocument(); myReport.Load(reportPath); DataTable dtx1 = new clsDyCrystalReportCore().dtx(ds.Tables[0]); int left = 100; #region 设置每列显示的数据和宽度 for (int i = 0; i < NodeList.Count; i++) { //设置公式字段对应的数据库字段 myReport.DataDefinition.FormulaFields["colu" + (i + 1).ToString()].Text = "{CryReport.colu" + (i + 1) + "}"; //设置公式字段的文本 myReport.DataDefinition.FormulaFields["mt" + (i + 1).ToString()].Text = "\"" + NodeList[i].Attributes["ChinesName"].Value + "\""; //设置宽度和左边偏移量 FieldObject fo; fo = (FieldObject)myReport.ReportDefinition.ReportObjects["colu" + (i + 1)]; //fo.Height = 567 * 3; int width = int.Parse(NodeList[i].Attributes["Width"].Value); fo.Width = width; fo.Left = left; fo.Top = 30; fo = (FieldObject)myReport.ReportDefinition.ReportObjects["mt" + (i + 1)]; //fo.Height = 567 * 3; fo.Width = width; fo.Left = left; fo.Top = 760; left += width+100; } #endregion HideColu(NodeList.Count, myReport); myReport.DataDefinition.FormulaFields["title"].Text = "\"" + title + "\""; //myReport.Database.Tables[0].ApplyLogOnInfo(GetConnectionInfo());//设置报表数据库连接信息 myReport.SetDataSource(dtx1); CrystalReportViewer1.SeparatePages = Separate; CrystalReportViewer1.ReportSource = myReport; CrystalReportViewer1.DataBind(); CrystalReportViewer1.RefreshReport(); } } }