我將項目中的一部分提煉出來,寫了這個Demo. 先說一下需求, 從 API接口, 獲取數據源, 調用RDLC 生成PDF文件. (后面還有涉及到使用福昕PDf閱讀器進行設置文件自定義內容,以供外部程序使用,這里就不列舉.)
現在要生成以下格式的PDF文件, 其中 "職稱信息" 會有多個, "項目負責人登記信息(本市在建項目)" 也會有多個. 如下如
很明顯, 這里涉及到的數據源,會有多個. 我將這個 拆成3個數據源.
第一個: 人員基本信息+pdf信息
第二個: 職稱信息List
第三個: 項目負責人登記信息(本市在建項目)
特別說明: 項目負責人登記信息(本市在建項目) 下面的那一行字, 截止至xxxx詳細信息是動態的,這里也是一個字段, 我將 列表以外的 字段, 都歸為 第一個數據源里面.
第一步: 構建 實體類

/// <summary> /// 人員基本信息 /// </summary> public class Ryjbxx { /// <summary> /// pdf文件編號 /// </summary> public string pdfbh { get; set; } /// <summary> /// 生成時間 /// </summary> public string scsj { get; set; } /// <summary> /// 姓名 /// </summary> public string xm { get; set; } /// <summary> /// 證件號 /// </summary> public string zjh { get; set; } /// <summary> /// 證件類型 /// </summary> public string zjlx { get; set; } /// <summary> /// 在建項目截止日期 /// </summary> public string zjxm_jzrq { get; set; }

/// <summary> /// 人員職稱信息 /// </summary> public class Ryzcxx { /// <summary> /// 人員職稱 /// </summary> public string ryzc { get; set; } /// <summary> /// 證書編號 /// </summary> public string zsbh { get; set; } /// <summary> /// 批准日期 /// </summary> public string pzrq { get; set; } /// <summary> /// 發證機構 /// </summary> public string fzjg { get; set; } }

/// <summary> /// 在建項目信息 /// </summary> public class Ryzjxmxx { /// <summary> /// 項目名稱 /// </summary> public string xmmc { get; set; } /// <summary> /// 合同信息報送編號 /// </summary> public string htxxbsbh { get; set; } /// <summary> /// 合同類別 /// </summary> public string htlb { get; set; } }
第二步: 業務類,獲取數據源
我這里做了一下數據模擬.

public class DataSourceBLL { /// <summary> /// 獲取人員基本信息 /// </summary> /// <returns></returns> public List<Ryjbxx> GetRyjbxxList() { List<Ryjbxx> list = new List<Ryjbxx>(); Ryjbxx item = new Ryjbxx() { pdfbh = "GR201809000001", scsj = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), xm = "張三", zjh = "420117198008065923", zjlx = "身份證", zjxm_jzrq = "截止至"+DateTime.Now.ToString("yyyy年MM月dd日") }; list.Add(item); return list; } /// <summary> /// 獲取在建項目信息 /// </summary> /// <returns></returns> public List<Ryzjxmxx> GetRyzjxmxxList() { List<Ryzjxmxx> list = new List<Ryzjxmxx>(); Ryzjxmxx itme1 = new Ryzjxmxx() { htlb = "施工", htxxbsbh = "W2015080136330", xmmc = "延吉中路(雙陽路-營口路)道路整治工程" }; Ryzjxmxx itme2 = new Ryzjxmxx() { htlb = "施工", htxxbsbh = "W2015080136316", xmmc = "阿里巴巴(上海)物聯網技術應用中心" }; list.Add(itme1); list.Add(itme2); return list; } /// <summary> /// 獲取人員職稱信息 /// </summary> /// <returns></returns> public List<Ryzcxx> GetRyzcxxList() { List<Ryzcxx> list = new List<Ryzcxx>(); Ryzcxx item = new Ryzcxx() { zsbh = "滬xxxxx號", ryzc = "初級會計師", fzjg = "上海XXX機構", pzrq = "2017年2月3日" }; list.Add(item); return list; } }
第三步:畫RDLC
1. 新建類庫 RdlcDemoBLL, 目標框架 .NET Framework 4
2.添加程序集引用 Microsoft.ReportViewer.WebForms.dll ,System.Web.dll, System.Web.Extensions.dll
3.新建文件夾 RDLC,新建 報表 GRPdfTemp.rdlc
4.編輯RDLC報表, 大概是下面這個樣子.
然后就遇到一個問題, 現在 現在只有一個數據集, 其他的怎么添加進來呢?
這篇文章 主要點,就在這里.
5.新建一個rdlc, 拉一個 表, 可用數據集 選擇 Ryjbxx,
再新建一個rdlc, 拖一張表, 可用數據集 選擇 Ryzjxmxx
6. 后面2個 里面的 數據字典,拷貝到第一個 rdlc里面.並且更改 DataSource 和DataSet 名稱
右鍵GRPdfTemp.rdlc ==> 打開方式 ==>選擇 XML(文本)編輯器
拉到最下面, 可以看到 <DataSources> 節點和 <DataSets>節點
7.將 以上兩張 rdlc中的 DataSource 部分, 拷貝到 GRPdfTemp.rdlc 的 DataSources 節點里面, 現在改一下DataSources 的 Name屬性 <DataSource Name="RdlcDemoBLLModels">
以上兩張 rdlc中的 DataSet部分 ,拷貝到 GRPdfTemp.rdlc 的 DataSets 里面 ,然后改一下 DataSet 的Name 屬性 <DataSet Name="DataSet1">, 還有 <Query>節點里面的 <DataSourceName>
8. 現在 GRPdfTemp.rdlc 里面 <DataSources> 下面有3個 <DataSource>,如下所示
<DataSources> <DataSource Name="DataSource_Ryjbxx"> <ConnectionProperties> <DataProvider>System.Data.DataSet</DataProvider> <ConnectString>/* Local Connection */</ConnectString> </ConnectionProperties> <rd:DataSourceID>af7df84f-629d-422c-8be7-57ce146074ed</rd:DataSourceID> </DataSource> <DataSource Name="DataSource_Ryzcxx"> <ConnectionProperties> <DataProvider>System.Data.DataSet</DataProvider> <ConnectString>/* Local Connection */</ConnectString> </ConnectionProperties> <rd:DataSourceID>d37e0668-2343-42cd-83f5-77c9fd7f070a</rd:DataSourceID> </DataSource> <DataSource Name="DataSource_Ryzjxmxx"> <ConnectionProperties> <DataProvider>System.Data.DataSet</DataProvider> <ConnectString>/* Local Connection */</ConnectString> </ConnectionProperties> <rd:DataSourceID>960a9437-ce82-473b-9466-91dbfa9eadd4</rd:DataSourceID> </DataSource> </DataSources>
對應的 3個DataSet
9 這里就能選到數據源了
10 如果你不下心選錯了 DataSource, 后面不能重新選,只能 改 rdlc 原代碼 xml信息了.
每一張表是 一個 <Tablix Name="Tablix1">, 指定數據集 <DataSetName> 節點, 更改里面的 對應的 名字, 可以選到 對應數據源下面的字段.
第四步: 調用RDLC模板 生成PDF文件,

public class CreateRyxxPdfBLL { public void CreatePdfByRdlc() { Trace.WriteLine("生成Pdf開始"); string rdlPath = System.AppDomain.CurrentDomain.BaseDirectory + "\\RDLC\\GRPdfTemp.rdlc"; DataSourceBLL dataSourceBLL = new DataSourceBLL(); List<Ryjbxx> list1 = dataSourceBLL.GetRyjbxxList(); List<Ryzcxx> list2 = dataSourceBLL.GetRyzcxxList(); List<Ryzjxmxx> list3 = dataSourceBLL.GetRyzjxmxxList(); byte[] pdfByte = CreatePdfFromRdlc(list1, list2, list3, rdlPath); string savepath = string.Format(@"d:\grpdf_{0}_{1}.pdf", list1[0].zjh, DateTime.Now.ToString("yyyyMMddHHmmssfff")); File.WriteAllBytes(savepath, pdfByte); Trace.WriteLine("生成Pdf結束"); } public byte[] CreatePdfFromRdlc(List<Ryjbxx> list1, List<Ryzcxx> list2,List<Ryzjxmxx> list3, string rdlPath) { try { ReportViewer viewer = new ReportViewer(); viewer.ProcessingMode = ProcessingMode.Local; viewer.LocalReport.ReportPath = rdlPath; ReportDataSource ds1 = new ReportDataSource() { Name = "DataSet1", Value = list1 }; ReportDataSource ds2 = new ReportDataSource() { Name = "DataSet2", Value = list2 }; ReportDataSource ds3 = new ReportDataSource() { Name = "DataSet3", Value = list3 }; viewer.LocalReport.DataSources.Add(ds1); viewer.LocalReport.DataSources.Add(ds2); viewer.LocalReport.DataSources.Add(ds3); byte[] fileContent = viewer.LocalReport.Render("pdf"); return fileContent; } catch (Exception ex) { throw ex; } } }
生成結果樣圖
程序源代碼 : 點擊下載