ASP.NET中GridView行命令按钮动态打开Crystal Report及代码问题
Hey,我帮你梳理下这个场景下的实现方案,同时排查加入Crystal Report后容易踩的坑:
一、实现Print按钮触发Crystal Report的核心步骤
首先得把基础配置和代码逻辑捋顺:
- 先确保你的VS2010安装了Crystal Reports for Visual Studio 2010,项目里添加好
CrystalDecisions.CrystalReports.Engine、CrystalDecisions.Shared、CrystalDecisions.Web这几个引用,页面里也可以拖个CrystalReportViewer控件先测试下。 - 给GridView的最后一列改成
TemplateField,把Print按钮放进去,绑定好命令参数(比如支票ID)和点击事件:<asp:TemplateField HeaderText="操作"> <ItemTemplate> <asp:Button ID="btnEdit" Text="Edit" CommandName="Edit" runat="server" /> <asp:Button ID="btnDelete" Text="Delete" CommandName="Delete" runat="server" /> <asp:Button ID="btnSubmit" Text="Submit" CommandName="Submit" runat="server" /> <asp:Button ID="btnPrint" Text="Print" runat="server" OnClick="btnPrint_Click" CommandArgument='<%# Eval("ChequeID") %>' /> </ItemTemplate> </asp:TemplateField> - 写
btnPrint_Click的后台逻辑,核心是加载报表、传参,然后跳转到专门的报表页面:protected void btnPrint_Click(object sender, EventArgs e) { Button printBtn = (Button)sender; GridViewRow targetRow = (GridViewRow)printBtn.NamingContainer; int chequeId = Convert.ToInt32(printBtn.CommandArgument); // 加载报表文件 ReportDocument chequeReport = new ReportDocument(); // 替换成你实际的报表路径 string reportPath = Server.MapPath("~/Reports/ChequeDetailsReport.rpt"); chequeReport.Load(reportPath); // 给报表传参数(比如当前选中的支票ID) chequeReport.SetParameterValue("ChequeID", chequeId); // 如果报表需要直接绑定数据源,也可以在这里设置 // chequeReport.SetDataSource(GetChequeDataById(chequeId)); // 把报表对象存到Session里,因为回发时需要保持对象状态 Session["CurrentChequeReport"] = chequeReport; // 跳转到专门的报表展示页面 Response.Redirect("~/ChequeReportViewer.aspx"); } - 新建一个
ChequeReportViewer.aspx页面,专门用来显示报表:<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="ChequeReportViewer.aspx.cs" Inherits="YourProjectNamespace.ChequeReportViewer" %> <%@ Register Assembly="CrystalDecisions.Web, Version=13.0.2000.0, Culture=neutral, PublicKeyToken=692fbea5521e1304" Namespace="CrystalDecisions.Web" TagPrefix="CR" %> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>Cheque Print Preview</title> </head> <body> <form id="form1" runat="server"> <CR:CrystalReportViewer ID="CrystalReportViewer1" runat="server" AutoDataBind="true" HasPrintButton="true" HasExportButton="true" /> </form> </body> </html> - 这个报表页面的后台
Page_Load里取出Session里的报表对象:protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack && Session["CurrentChequeReport"] != null) { ReportDocument report = (ReportDocument)Session["CurrentChequeReport"]; CrystalReportViewer1.ReportSource = report; CrystalReportViewer1.DataBind(); } }
二、排查加入Crystal Report后常见的程序异常
下面是你可能遇到的异常和对应的解决办法:
- 异常:找不到Crystal Reports相关的程序集
解决:除了添加项目引用,还要在web.config里添加程序集绑定重定向,确保版本一致:<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="CrystalDecisions.CrystalReports.Engine" publicKeyToken="692fbea5521e1304" culture="neutral" /> <bindingRedirect oldVersion="0.0.0.0-13.0.2000.0" newVersion="13.0.2000.0" /> </dependentAssembly> <dependentAssembly> <assemblyIdentity name="CrystalDecisions.Shared" publicKeyToken="692fbea5521e1304" culture="neutral" /> <bindingRedirect oldVersion="0.0.0.0-13.0.2000.0" newVersion="13.0.2000.0" /> </dependentAssembly> </assemblyBinding> - 异常:报表文件加载失败(路径错误)
解决:一定要用Server.MapPath获取服务器端的物理路径,不要直接写相对路径;同时把报表文件的复制到输出目录属性设置为「如果较新则复制」。 - 异常:Session丢失导致报表无法显示
解决:不要尝试序列化传递ReportDocument对象,直接存在Session里;另外确保web.config里Session状态是启用的:<sessionState mode="InProc" timeout="20" />。 - 异常:GridView动态生成后,Print按钮点击事件不触发
解决:动态生成GridView的代码要放到Page_Init事件里,而不是Page_Load——因为ASP.NET的事件生命周期中,控件需要在Init阶段重建才能正确绑定回发事件,还要给动态控件设置唯一的ID。 - 异常:权限不足(无法读取报表或数据库)
解决:给报表所在文件夹添加IIS应用程序池身份的读写权限;如果报表连接数据库,确保连接字符串里的账号有足够的访问权限,用集成身份验证时要给应用程序池配置对应的数据库权限。
三、额外注意事项
- VS2010对应的Crystal Reports版本是13.0.x,部署到服务器时一定要安装Crystal Reports Runtime for .NET Framework 4,否则报表无法正常运行。
- 测试时可以先单独运行报表展示页面,确保报表能正常加载数据,再整合到GridView的Print按钮逻辑里,这样更容易排查问题。
- 如果是多用户场景,要注意Session的隔离性,每个用户的报表对象存在各自的Session中,避免互相干扰。
内容的提问来源于stack exchange,提问作者AKA
相关产品推荐
相关产品推荐

