2016年8月2日 星期二

[RDLC] 使用子報表(SubReport)從既有RDLC建立多筆報表

 #RDLC   #Report viewer   #SSRS



Introduction


小弟日前完成了單張報表RDLC(以單號=XXX帶出)的情況下,使用者提出是否可同時列印多張報表(一次帶入多個單號)的需求;
因為這張報表很複雜,不太可能為了一次列印多張而重拉RDLC

這時候比較聰明的作法就是利用「子報表」Sub-Report搭配「資料表」DataTable的方式, 重複使用既有已經設計好的報表來完成多張報表的需求


Related articles



我們將延續以上文章的範例,實作利用子報表完成多張報表的功能。



Implement


以下是此範例將會新增的項目~

 

資料集:DataSetCityName

首先,我們必須設計一個DataSet來存放帶出多張報表的Key(參數值),例如本例的城市名稱 將用來作為帶入子報表的資料庫查詢參數。



RDLCCityCollection.rdlc (母報表)

RDLC加入前一步驟的資料集。

 

另外我們在run time時,會將DataSetCityName裡面的Name值,注入到子報表作為參數做查詢。 所以這一張母報表需要加入子報表的資料來源 (但是不需要子報表的資料集)

做法是先加入子報表的資料集,此時一併帶入資料來源,接著再移除子報表的資料集。


接著重頭戲來了,開始設計RDLC!!
先加入資料表DataTable


我們只需資料表留一列,並加入資料集:DataSetCityName[Name]
接著插入一個群組內-下方的資料列,並加入SubReport


插入子報表


設定子報表要使用哪一張既有的RDLC,本例的子報表是 : City

 

在子報表控制項加入一個參數,其值指向DataSetCityName[Name]



 


到這邊已經完成了母報表RDLC的設計, 重點在於
l   帶入多個城市名稱給母報表RDLC
l   指派每個城市名稱給子報表RDLC作為查詢參數


RDLCCity.rdlc (子報表)

子報表只有一個地方需要修改,由於子報表的查詢參數是由母報表帶入,所以需要加入一個報表參數: CityName




ASPX:帶入資料到母報表及子報表的ReportViewer

ASPX請自行加入ReportViewerScriptManager控制項。

l   Page_Load

以下Sample code是在Page_Load時,利用Url parameter帶入母報表所需的多個城市名稱,再存入DataSet帶入到母報表的RDLC

protected void Page_Load(object sender, EventArgs e)
{
            if (!IsPostBack)
            {
                var qStr = Request.QueryString["cityNames"].ToString();
                char[] separators = new char[] { ',' };
                string[] cityNames = qStr.Split(separators);

                try
                {

                    rptViewer.LocalReport.SetBasePermissionsForSandboxAppDomain(new PermissionSet(PermissionState.Unrestricted));
                    rptViewer.ShowPrintButton = true;
                    rptViewer.ProcessingMode = ProcessingMode.Local;
                    rptViewer.LocalReport.EnableExternalImages = true;
                    rptViewer.LocalReport.ReportPath = Server.MapPath("~/Reports/Rdlc/CityCollection.rdlc");
                    rptViewer.LocalReport.DataSources.Clear();

                    #region MainReport
                    DataSetCityName ds = getDataSet(cityNames.ToList());
                    ReportDataSource datasource = new ReportDataSource("DataSetCityName", ds.Tables[0]);
                    rptViewer.LocalReport.DataSources.Add(datasource);
                    #endregion

                    #region SubReport
                    rptViewer.LocalReport.SubreportProcessing += new SubreportProcessingEventHandler(SetSubDataSource);
                   
                    #endregion

                    rptViewer.LocalReport.Refresh();
                }
            }
}

private DataSetCityName getDataSet(List<string> cityNames)
{               
             var dataset = new DataSetCityName();
             var dataTable = dataset.Tables[0];
             foreach (var cn in cityNames)
             {
                var dr = dataTable.NewRow();
                dr["Name"] = cn;
                dataTable.Rows.Add(dr);
             }
             return dataset;
}

至於子報表的資料要如何帶入? 設定rptViewer.LocalReport.SubreportProcessing 這個delegate eventhandler來另行處理。

底下是負責SubreportProcessingevent,可以看到帶出子報表的方式其實很熟悉,
l   取得查詢的參數值(city)
l   呼叫Store Procedure
l   將資料放入DataSet
l   DataSet放入子報表RDLCDataSource

唯一的不同在於查詢的參數值,改由報表參數帶入,也就是我們在上面其中一個步驟加入到子報表的參數:CiteName



public void SetSubDataSource(object sender, SubreportProcessingEventArgs e)
{
                var city = e.Parameters["CityName"].Values.First();

                DataSetCity dsCity = getCityData(city);
                ReportDataSource datasource = new ReportDataSource("DataSetCity", dsCity.Tables[0]);
                e.DataSources.Add(datasource);

}

private DataSetCity getCityData(string cityName)
{
       var rtnVal = new DataSetCity();

       var connString = ConfigurationManager.ConnectionStrings["JbDbContext"].ConnectionString;
       var sqlConn = new SqlConnection(connString);
       SqlCommand cmdReport = new SqlCommand("usp_getCitys", sqlConn);
       SqlDataAdapter daReport = new SqlDataAdapter(cmdReport);
       using (cmdReport)
       {
                    SqlParameter questionIdPrm = new SqlParameter("@CityName", cityName);
                    cmdReport.CommandType = CommandType.StoredProcedure;
                    cmdReport.Parameters.Add(questionIdPrm);

                    daReport.Fill(rtnVal, "DataTableCity");

       }
       return rtnVal;
}


執行結果

原本單筆的報表(City.rdlc)
 

多筆的報表(CityCollection.rdlc)






Reference

沒有留言:

張貼留言