我是Crystal report的新手,应用程序位于ASP.net 3.5和MySQL 5.1中,将在起始日期和结束日期之间开发报表,报表的第一页显示得很好,但当我尝试在另一页上导航时,出现了错误,如缺少参数值,与在打印和导出操作中出现的错误相同
提前谢谢
公共部分类预订声明:System.Web.UI.Page
{
//DAL is my Data Access Layer Class
//书是报告类的
DAL obj = new DAL();
Book bkStmt = new Book();
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
//crvBooking is Crystal Report Viewer
//reportFill method is to fill Report
reportFill();
crvBooking.EnableViewState = true;
crvBooking.EnableParameterPrompt = false;
}
/* Also try reportFill() out side !IsPostBack but didn't work */
//Check if the parmeters have been shown.
/* if ((ViewState["ParametersShown"] != null) && (ViewState["ParametersShown"].ToString() == "True"))
{
bkStmt.SetParameterValue(0, "20/04/2010");
bkStmt.SetParameterValue(1, "20/04/2010");
}*/
}
protected void crvBooking_navigate(object sender, CrystalDecisions.Web.NavigateEventArgs e)
{
// reportFill();
}
protected void reportFill()
{
//bkStmt.rpt is Report file
//bookingstatment is View
//bkStmt is ReportClass object of Book
string rptPath = "bkStmt.rpt";
string query = "select * from bookingstatment";
crvBooking.RefreshReport();
crvBooking.Height = 600;
crvBooking.Width = 900;
bkStmt.ResourceName = rptPath;
String dtFrm = bkStmt.ParameterFields[0].CurrentValues.ToString();
obj.SetCommandType(CommandType.Text);
obj.CommText = query;
DataTable dtst = obj.GetDataTable();
crvBooking.ParameterFieldInfo.Clear();
ParameterDiscreteValue discretevalue = new ParameterDiscreteValue();
discretevalue.Value = "20/04/2010"; // Assign parameter
ParameterValues values = new ParameterValues();
values.Add(discretevalue);
bkStmt.SetDataSource(dtst);
ViewState["ParametersShown"] = "True";
crvBooking.EnableViewState = true;
bkStmt.DataDefinition.ParameterFields[0].ApplyCurrentValues(values);
bkStmt.DataDefinition.ParameterFields[1].ApplyCurrentValues(values);
crvBooking.ReportSource = bkStmt;
}
}
最佳答案
出现此问题似乎是因为当回发发生时,Crystal Reports不会在其ViewState中保留其参数值。因此,当CrystalReportViewer
试图再次加载其用作ReportClass
的ReportSource
时,参数值不再存在。
我们成功使用的一种解决方案是,在设置了ReportClass
的所有参数值之后,将Session
保存到CrystalReportViewer
中,然后在Page_Init
事件中的每次回发时将其加载到Session
中。例如:
// instantiate the Crystal Report
var report = new DeliveryLabelsSingle();
// set the required parameters
report.DataSourceConnections[0].SetConnection("DBServer", "DatabaseName", "DatabaseUser", "DatabasePassword");
report.SetParameterValue("@Param1", "val1");
report.SetParameterValue("@Param2", "val2");
// set the data source of the viewer
crvLabels.ReportSource = report;
// save the report object in session for postback binding
Session["rptDeliveryLabels"] = report;
然后页面的页面初始化事件如下所示:
protected void Page_Init(object sender, EventArgs e)
{
if (IsPostBack) {
if (Session["rptDeliveryLabels"] != null) {
// cast the report from object to ReportClass so it can be set as the CrystalReportViewer ReportSource
// (All Crystal Reports inherit from ReportClass, so it serves as an acceptable data type through polymorphism)
crvLabels.ReportSource = (ReportClass)Session["rptDeliveryLabels"];
}
}
}
这样,我们将始终为查看器设置一个报表对象,该对象已经用适当的值初始化。
这种方法需要记住的一点是,您可能会很快填满服务器内存,特别是当您有很多用户生成许多不同的报告时。所以一些家政工作已经准备好了。我们通过为包含报表的所有ASP.NET页面实现一个基类来实现这一点(因此这个报表加载代码)。在这个基类中,我们将所有可能的
Session
报告变量设置为空。就像这样:// class definition for ASP.NET page containing CrystalReportViewer & associated report(s)
public partial class DeliveryLabelPrint : BaseReport
那么BaseReport的定义如下:
public class BaseReport : System.Web.UI.Page
{
protected override void OnLoad(EventArgs e)
{
if (!IsPostBack) {
for (var i = 0; i < Session.Count; i++) {
var sv = Session[i];
// if this session variable contains a Crystal Report, destroy it
if (sv is ReportClass) {
sv = null;
}
}
base.OnLoad(e);
}
}
}
通过这种方式,可以确保任何用户在任何给定时间内存中都只有一个报告。
如果内存是一个问题,即使使用这种方法,也可以将单个变量值存储在
Page_Init
中,然后在CrystalReportViewer.ReportSource
中实例化一个新报告,并在将其分配给ReportClass
之前用保存的值重新填充它。但是在我们的例子中,有40个用户每天提取50多个不同的报告,这种存储对象的实现和伴随的管理,自从应用程序3年前上线以来,我们没有遇到任何内存问题。我仍然建议在将此解决方案投入生产之前进行适当的负载测试和监视,因为结果可能因具体实现而异。