使用自定义数据源创建 RDLC 报表
使用自定义列表创建报表,并使用 RDLC 和报表查看器创建带子报表的报表。
介绍
我正在做一个项目,任务是评估可以集成到我们的项目中或非常适合我们项目的不同报表引擎。我偶然发现了 Microsoft 提供的一个免费报表系统。虽然一开始它对我来说非常难以理解,但在深入研究之后,我非常喜欢它。
我在互联网、相关论坛上进行了搜索,经过深入研究,我在此发布我的发现。本课程适合那些对 Web 应用程序、类库及其使用方法有基本了解的人,目标受众是报表领域的新手。
学习课程
- 创建我们的自定义数据(使用列表)
- 使用基于自定义数据的 RDLC 创建报表
- 发布报表
- 创建第二个自定义数据(使用列表)
- 创建子报表并将其附加到主报表
- 为子报表添加参数,并从主报表中传递数据
- 添加代码以处理子报表
- 再次发布报表
创建我们的自定义数据(使用列表)
- 通过选择 **文件->新建->项目** 创建一个 Web 应用程序,在 Visual Studio 2010 中选择 ASP.NET Web 应用程序,并命名为 **CpReportCustomData**。
- 同样,现在添加一个类库,它将充当我们的数据源,以保持代码的简洁和分离,假设我们的类库名称为 *CpReportCustomData.Data*。删除项目中的默认 class1.cs。
- 现在,在 **CpReportCustomData.Data** 中添加一个名为
Employee
的新类,完成后它看起来会像这样 - 现在添加我们的
CustomDS
类,它将充当员工列表和报表之间的中介。我们的CustomDS
类看起来会像这样 - 编译并构建类库。
- 在 Web 应用程序中添加你的类库的引用。
public class Employee
{
public int ID { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
看,我创建了一个基本的类,没有什么特别的。
public class CustomDS
{
private static List <employee> _lstEmployee = null;
public static List <employee> GetAllEmployees()
{
if (_lstEmployee == null)
{
_lstEmployee = new List <employee> ();
_lstEmployee.Add( new Employee()
{
ID=1,
Name="Alok",
Age=30
});
_lstEmployee.Add(new Employee()
{
ID = 2,
Name = "Ashish",
Age = 30
});
_lstEmployee.Add(new Employee()
{
ID = 3,
Name = "Jasdeep",
Age = 30
});
_lstEmployee.Add(new Employee()
{
ID = 4,
Name = "Kamlesh",
Age = 31
});
}
return _lstEmployee;
}
}
使用基于自定义数据的 RDLC 创建报表
- 现在你的数据设置已完成。添加一个报表,右键单击 Web 应用程序 -> 添加新项 -> 报表 -> 报表向导,将其命名为 rptAllEmployees。
- 添加报表后,将打开数据集属性窗口,选择数据集名称为 **DSALLEmployee**,选择数据源为 **cpReportCustomData.Data**,并在可用数据集中选择 **CustomDS(GetAllEmployees)**。完成此设置后,字段列表控件将显示所有可用的数据字段。
- 现在选择报表中的所有可用字段,并取消选中“显示子报表”和“展开组”复选框。
- 基本框架将完成,你的报表看起来会像这样
这里有两个选项,要么尝试自己构建报表,要么借助报表向导根据 DS 创建一个骨架。
重要提示:数据集名称非常重要,每次填充报表数据时都必须提供此名称。稍后我们会回到这一点。
发布报表
- 现在,在 *default.aspx* 文件中,从工具箱添加报表查看器控件(命名为 **rptViewer**),因为报表查看器还需要
ScriptManger
,所以也添加它。 - 现在,通过在智能标记窗口中选择来将我们的报表(*rptAllEmployees.rdlc*)分配给
rptViewer
。 - 现在点击“选择数据源”,然后在弹出的对话框中点击“确定”。它会自动添加我们 DS 的引用。如果你看到代码隐藏,我们的报表查看器 HTML 标签看起来会像这样
- 运行并查看报表。
<rsweb:ReportViewer ID="rptViewer" runat="server" Width="100%"
Font-Names="Verdana" Font-Size="8pt" InteractiveDeviceInfos="(Collection)"
WaitMessageFont-Names="Verdana" WaitMessageFont-Size="14pt">
<LocalReport ReportPath="rptAllEmployees.rdlc">
<DataSources>
<rsweb:ReportDataSource DataSourceId="ObjectDataSource1" Name="DSAllEmployee" />
</DataSources>
</LocalReport>
</rsweb:ReportViewer>
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
SelectMethod="GetAllEmployees" TypeName="CpReportCustomData.Data.CustomDS">
</asp:ObjectDataSource>
到目前为止的总结
- 创建了一个自定义数据类,并使用类库中的静态函数将其作为类对象列表返回
- 使用报表向导创建报表,并选择类库作为数据源,静态函数作为数据集
- 在网页上添加了报表查看器控件,将其附加到我们的报表,并将其绑定到数据集以显示数据
创建第二个自定义数据(使用列表)
- 在 **CpReportCustomData.Data** 类库中添加一个名为
EmployeeFamily
的新类,完成后它看起来会像这样。这里你可以将 *ID* 列视为指向员工“ID”字段的外键。 - 同样,在
CustomDS
类中添加 get 函数,它将返回一个员工家庭列表。完成后,它看起来会像这样 - 构建类库以更新所做的更改。
public class EmployeeFamily
{
public int ID { get; set; }
public String Name { get; set; }
public string Relation { get; set; }
}
private static List<EmployeeFamily> _lstEmployeeFamily = null;
public static List<EmployeeFamily> GetAllEmployeeFamily()
{
if (_lstEmployeeFamily == null)
{
_lstEmployeeFamily = new List<EmployeeFamily>();
_lstEmployeeFamily.Add(new EmployeeFamily()
{
ID = 1,
Name = "AlokWife",
Relation = "Wife"
});
_lstEmployeeFamily.Add(new EmployeeFamily()
{
ID = 1,
Name = "AlokDaughter",
Relation = "Daughter"
});
_lstEmployeeFamily.Add(new EmployeeFamily()
{
ID = 2,
Name = "AshishWife",
Relation = "Wife"
});
_lstEmployeeFamily.Add(new EmployeeFamily()
{
ID = 3,
Name = "JasdeepFather",
Relation = "Father"
});
_lstEmployeeFamily.Add(new EmployeeFamily()
{
ID = 3,
Name = "JasdeepMother",
Relation = "Mother"
});
_lstEmployeeFamily.Add(new EmployeeFamily()
{
ID = 4,
Name = "KamleshWife",
Relation = "Wife"
});
_lstEmployeeFamily.Add(new EmployeeFamily()
{
ID = 4,
Name = "KamleshDaughter",
Relation = "Daughter"
});
}
return _lstEmployeeFamily;
}
创建子报表并将其附加到主报表
- 按照我在“使用基于自定义数据的 RDLC 创建报表”中创建报表的步骤进行操作,并将名称设置为
rptEmployeeFamily
而不是rptAllEmployees
,选择数据集名称为DSEmployeeFamily
,并使用CustomDS(GetAllEmployeeFamily)
而不是CustomDS(GetAllEmployees)
。 - 所有设置完成后,我们的报表看起来会像这样
- 现在导航到 **rptAllEmployees**,右键单击 Age 字段,插入行 -> 组内 - 向下。
- 合并新添加行中的 Name 和 Age 列单元格,并从工具箱向其中添加子报表并命名为 **rptEmpFamily**。出于设计目的,你也可以在左侧添加一个名为“家庭详情”的文本框,并为其提供独特的样式
- 在 **rptEmpFamily** 属性窗口中,将报表名称设置为 **rptEmployeeFamily**,现在我们的报表看起来会像这样
为子报表添加参数,并从主报表中传递数据
- 现在我们已经将子报表添加到主报表中,我们需要将有关它的信息传递给子报表,所以我们打开 **rptEmployeeFamily** 的报表数据视图(视图->报表数据),右键单击参数以添加报表的 id 参数。
- 将名称输入为 **EmpID**,类型为 Integer,并允许传递 null 值。
- 现在在 rptAllEmployees 中,打开子报表属性,导航到参数,将 Name 设置为 EmpID,将 Value 设置为 [ID],然后单击“确定”保存。此步骤确保我们在主报表的每次数据集迭代中都将 ID 作为参数传递给子报表。
- 现在我们的报表已完成,我们必须在主报表查看器窗口中添加代码来处理子报表处理。
添加代码以处理子报表
- 在
page_load
中添加子报表处理事件处理程序(你可以将其添加到任何地方,但应该在填充报表数据之前)。 - 现在在
LocalReport_SubreportProcessing
** 方法中,添加以下代码,代码解释在注释中。 - 你可以看到我们添加了名称为 **DSEmployeeFamily** 的数据源,还记得我告诉过你它很重要吗!由于使用了它,报表才能识别要填充哪些数据。
if (!Page.IsPostBack)
{
rptViewer.LocalReport.SubreportProcessing +=
new Microsoft.Reporting.WebForms.SubreportProcessingEventHandler(LocalReport_SubreportProcessing);
}
void LocalReport_SubreportProcessing(
object sender,
Microsoft.Reporting.WebForms.SubreportProcessingEventArgs e)
{
// get empID from the parameters
int iEmpID = Convert.ToInt32(e.Parameters[0].Values[0]);
// remove all previously attached Datasources, since we want to attach a
// new one
e.DataSources.Clear();
// Retrieve employeeFamily list based on EmpID
var employeeFamily = CpReportCustomData.Data.CustomDS.GetAllEmployeeFamily()
.FindAll(element => element.ID == iEmpID);
// add retrieved dataset or you can call it list to data source
e.DataSources.Add(new Microsoft.Reporting.WebForms.ReportDataSource()
{
Name = "DSEmployeeFamily",
Value = employeeFamily
});
}
再次发布报表
- 什么都不用做,坐着放松,Visual Studio 2010 会构建并运行报表。
兴趣点
特别鸣谢
- 我的父母,我的妻子和 Parkhi!
历史
- 2012 年 10 月 8 日:开始工作
- 2012 年 10 月 10 日:发布到 CodeProject