博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

ReportingService统计已打印标志

Posted on 2008-06-05 10:30  chgBlog  阅读(2167)  评论(6)    收藏  举报

    我们知道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,那样就可以完美解决这个问题了.