我们知道Microsoft 为了抗衡Crystal Reports 推出了Reporting Serviec ,利用.Net平台和SqlServer我们很容易开发适合客户的各种报表,Reporting Service部署管理也很方便简单.
前台页面调用后台Reporting Service的rdl文件一般采用.Net自带的ReportView控件,一个调用例子如下.
命名空间是using Microsoft.Reporting.WebForms;
ReportParameter[] p = {
new ReportParameter("pMLOG_Entity", dpMlog_Entity.SelectedValue.Trim ()),
new ReportParameter("pConsignee", txtConsignee .Text.Trim() ),
new ReportParameter("pFeeder_Vessel", txtFeederVessel .Text.Trim ()),
new ReportParameter("pFeeder_Voy", txtFeederVesselVoyage .Text .Trim ()),
new ReportParameter("pMother_Vessel", txtMotherVessel .Text.Trim ()),
new ReportParameter("pMother_Voy", txtMotherVesselVoyage .Text .Trim ()),
new ReportParameter("pFeeder_ETD_From", txtFeeETDFrom.Text.Trim ()),
new ReportParameter("pFeeder_ETD_To", FeeETDTo ),
new ReportParameter("pMother_ETD_From", txtMotherETDFrom .Text.Trim ()),
new ReportParameter("pMother_ETD_To", ETDTo ),
new ReportParameter("ServiceType", drpServiceType .SelectedValue ),
new ReportParameter("CUS_UID", txtCUSUID .Text .Trim () ),
new ReportParameter("CUS_Team", txtCUSTeam .Text .Trim () ),
};
this.LoadingSummaryReporter.ServerReport.ReportServerUrl = new Uri(http://192.168.2.80/reportserver);
this.LoadingSummaryReporter.ServerReport.ReportPath = "/StatisticalReport/Loading_Summary";
this.LoadingSummaryReporter.ServerReport.SetParameters(p);
this.LoadingSummaryReporter.ServerReport.Refresh();
这样就完成了.具体怎么制作Reporting Service不在本文讨论范围.
ReportView控件是Microsoft封装集成好的,并且目前不开源.只有简单是设置是否显示属性,比如是否显示导出,打印按钮等.但是如何导出,打印则对我们不可见.
我们的客户为了工作的需要,希望我们能提供是否打印的标记,因为业务量很大,他们有时自己不知道打印还是没打印,容易造成浪费纸张.
仔细研究国外一些资料,发现要想改成Microsoft的ReportView是不可能,主要是Microsoft不公开,连它继承的类库都不知道.没办法只有从客户端想办法,经过研究发现可行.客户端页面打印是调用如下JS函数:
if (ClientToolbarBill_PrintView_ctl01.LoadPrintControl(), false)
{
__doPostBack('Bill_PrintView$ctl01$ctl07$ctl00$ctl00','');
}
return false;
尽管生成名字是前缀加一些编码,但还是有规律的,比喻Bill_PrintView就是ReportView控件的名字,$ctl01$ctl07$ctl00$ctl00是根据一定规则生成的,大部分的时候
都是一样的,所以我们可以在客户端改写导出按钮的onlick事件,在PageLoad注册body的onload 事件如下:
bodyPrint.Attributes.Add("onload", "return defaultExcel('" + this.Bill_PrintView.ID.ToString() + "')");
defaultExcel函数如下
function defaultExcel(objId)
{
//默认Excel导出
var objselect=document.getElementById(objId+"_ctl01_ctl05_ctl00");
if(!objselect) return
for(var i=0;i<objselect.options.length;i++)
{
if(objselect.options[i].value == "EXCEL")
{
objselect.options[i].selected="selected";
break;
}
}
//获得Print按钮,添加事件
//Bill_PrintView_ctl01_ctl07_ctl00_ctl00
var objBtn=document.getElementById(objId+'_ctl01_ctl07_ctl00_ctl00');
if(!objBtn) return;
//重写导出js
objBtn.onclick= function()
{
var _o=document.getElementById("reportValue");
if(!_o) return ;
PageMethods.CallPrintData(_o.value);//
if (ClientToolbarBill_PrintView_ctl01.LoadPrintControl(), false)
{
__doPostBack('Bill_PrintView$ctl01$ctl07$ctl00$ctl00','');
//__doPostBack(eval(objId+'$ctl01$ctl07$ctl00$ctl00'),'');
}
return false;
}
}
关键是PageMethods.CallPrintData(_o.value)这个函数,这是一个Ajax回调服务器端的函数,我们在CallPrintData就可以调用后台代码在数据库中相应置标志了.
示例如下:
[WebMethod ]
[ScriptMethod]
public static string CallPrintData(string reportValue)
{
if (string.IsNullOrEmpty(reportValue)) return "";
string[] valuesArray = reportValue.Split('*');
string carrier_so = valuesArray.Length > 1 ? valuesArray[1] : string.Empty;
string id = valuesArray.Length >0?valuesArray[0]:string .Empty ;
STS.BLL.CarrierBookingInfos bll = new STS.BLL.CarrierBookingInfos();
if (!string.IsNullOrEmpty(carrier_so ))//one booking one carrier so print
{
bll.PrintByCarrierSo(carrier_so, id);
}
else//one Booking batch print
{
bll.PrintByBookingNo(id);
}
return "";
}
至此已完成了客户的要求.
总结:
本问题的解决是.Net 的一些知识的综合应用,用到了Reporting Sevice以及显示的ReportView控件,JS知识,以及Ajax方法.需要一定的.Net知识基础.
感兴趣的读者可以尝试研究.
是这种解决方法有缺点,就是我们在页面弹出打印机画面之前就已经写入了数据库,如果用户在弹出打印机之后选择放弃打印,我们的统计就会不准确.
对于这种问题暂时没有解决的办法,如果能在客户端捕捉到打印机确定打印事件,可以解决存在的问题,不过暂时还没研究出来.最好的解决办法是Microsoft公开
源代码,我们在服务器端重写ReportView,那样就可以完美解决这个问题了.
浙公网安备 33010602011771号