无法在ReportViewer aspx.net中显示数据表 [英] Can't Display DataTable in ReportViewer aspx.net
问题描述
我在ReportViewer控件中显示DataTable对象的内容时遇到困难.没有错误,页面上仅显示一个空白的报表查看器.我已经查看了在这里找到的各种类似问题中提出的解决方案,此处和
I am having difficulty displaying the contents of a DataTable object in a ReportViewer control. There are no errors, just a blank report viewer being shown on the page. I have looked at the solutions presented in various similar questions found here, here and here - that last one is particularly frustrating as the last comment says "let's continue this discussion in chat" with no answer provided and it is essentially my exact issue.
页面代码:
<div class="panel-body">
<rsweb:ReportViewer ID="ReportViewer1" runat="server" Width="100%">
<LocalReport ReportPath="reports\Report1.rdlc">
</LocalReport>
</rsweb:ReportViewer>
</div>
隐藏代码:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
string repstr = Request.Form["repId"];
int repId = -1;
int.TryParse(repstr, out repId);
CustomReport rpt = new CustomReport(repId);
data = rpt.ReportResult.Copy();//The report result property is a DataTable object that can have varying # of columns
data.TableName = "CustomReport";
ReportViewer1.ProcessingMode = ProcessingMode.Local;
ReportDataSource source = new ReportDataSource("CustomReport", data);
ReportViewer1.LocalReport.DataSources.Clear();
ReportViewer1.LocalReport.DataSources.Add(source);
ReportViewer1.DataBind();
ReportViewer1.LocalReport.Refresh();
ReportViewer1.Visible = true;
}
}
我已经验证了DataTable正在填充数据,并且通过调试,我已经验证了ReportViewer数据属性似乎也具有数据-只是不显示....
I have verified that the DataTable is being populated with data and through debugging I've verified that the ReportViewer data properties appear to have the data as well - it's just not being displayed....
任何帮助将不胜感激!
推荐答案
因此,在经过大量研究和谷歌搜索以及我很棒的开发同事的帮助之后,我遇到了一个解决方案,该解决方案实际上涉及到必须重建.rdlc的xml结构.文件以支持动态列.此方法有两个警告.1.您必须手动配置引用数据源的xml,以指向提供数据表的对象方法,因为报表设计器不支持此方法.我在下面包含了我的xml更改.2.您必须将表添加到报表定义中,该表仅包含一列和一行.也许有人可以做得更好.
So after a lot of research and googling and help from my awesome development colleagues I came across a solution that essentially involves having to reconstruct the xml structure of the .rdlc file in order to support dynamic columns. There are a couple of caveats to this approach. 1. You have to manually configure the xml referencing the datasource to point at your object method that provides the datatable as the report designer does not support this. I've included my xml changes below. 2. You have to add a table to the report definition with only one column and one row. Maybe somebody can do this better.
所以解决方案.首先是rdlc xml数据源配置:
So the solution. First the rdlc xml datasource config:
<DataSet Name="DataSet1">
<Query>
<DataSourceName>DataLayer</DataSourceName>
<!--//Put the table name of your datatable object here-->
<CommandText>CustomReportsDs</CommandText>
</Query>
<!--//This is a single empty field for mapping to the table control-->
<Fields>
<Field Name="ReportTitle">
<DataField>ReportTitle</DataField>
<rd:TypeName>System.String</rd:TypeName>
</Field>
</Fields>
<rd:DataSetInfo>
<!--//This must be configured to point to the method that supplies the datatable
//In my instance the DataSetName is the namespace of the object,
//TableName is the object that provides the method and
//ObjectDataSourceSelectMethod is the method that provides the datatable-->
<rd:DataSetName>DataLayer</rd:DataSetName>
<rd:TableName>CustomReport</rd:TableName>
<rd:ObjectDataSourceSelectMethod>ReportResult</rd:ObjectDataSourceSelectMethod>
<rd:ObjectDataSourceType>DataLayer.CustomReport, DataLayer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null</rd:ObjectDataSourceType>
</rd:DataSetInfo>
</DataSet>
接下来,您必须配置报告查看器以从内存流中接收报告定义:
Next you have to configure the report viewer to recieve the report definition from a memory stream:
//load the data
int repId = -1;
int.TryParse(Request.Form["repId"], out repId);
CustomReport rpt = new CustomReport(repId);
DataTable data = rpt.ReportResult.Copy();//The report result property is a DataTable object that can have varying # of columns
data.TableName = "CustomReportDs";
//setup the report viewer
ReportViewer1.ProcessingMode = ProcessingMode.Local;
ReportViewer1.LocalReport.ReportPath = string.Empty;
//prepare to load the report definition xml file
string ReportPath = Server.MapPath(@"\reports\Report1.rdlc");
//my datatable comes with "friendly" column headings - these don't work well as the xml requires cls compliant
//columnheadings so here we rename the columns in the data table but preserve the friendly names for use later
Dictionary<string, string> columns = new Dictionary<string, string>();
int counter = 0;
foreach(DataColumn col in data.Columns)
{
columns.Add("column"+counter.ToString(), col.ColumnName);
col.ColumnName = "column" + counter.ToString();
counter++;
}
//format the report definition xml
byte[] reportDefinitionBytes = Encoding.UTF8.GetBytes(ConfigurXMLReport(ReportPath, "CustomReportDs", columns).OuterXml);
//load the formatted report into the reportviewer
MemoryStream stream = new MemoryStream(reportDefinitionBytes);
ReportViewer1.LocalReport.LoadReportDefinition(stream);
//bind and display the data as normal
ReportDataSource source = new ReportDataSource("DataSet1", data);
ReportViewer1.LocalReport.DataSources.Clear();
ReportViewer1.LocalReport.DataSources.Add(source);
ReportViewer1.DataBind();
ReportViewer1.LocalReport.Refresh();
最后我有了这个方法,它是我在研究问题时发现的其他人编写的几种方法的修改版本
Finally I have this method, which is a modified version of several methods written by others that I found during my research on the problem
public static XmlDocument ConfigurXMLReport(string path, Dictionary<string, string> Columns)
{
XmlDocument objXmlDocument = new XmlDocument();
objXmlDocument.Load(path);
XmlNamespaceManager mgr = new XmlNamespaceManager(objXmlDocument.NameTable);
string uri = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition";
mgr.AddNamespace("df", uri);
//locate and create nodes for cloning and modification
XmlNode tablixCols = objXmlDocument.SelectSingleNode("/df:Report/df:Body/df:ReportItems/df:Tablix/df:TablixBody/df:TablixColumns", mgr);
XmlNode dataField = objXmlDocument.SelectSingleNode("/df:Report/df:DataSets/df:DataSet/df:Fields/df:Field", mgr);
XmlNode tablixMember = objXmlDocument.SelectSingleNode("/df:Report/df:Body/df:ReportItems/df:Tablix/df:TablixColumnHierarchy/df:TablixMembers/df:TablixMember", mgr);
XmlNode rowHeaders = objXmlDocument.SelectSingleNode("/df:Report/df:Body/df:ReportItems/df:Tablix/df:TablixBody/df:TablixRows/df:TablixRow", mgr);
XmlNode rowValues = rowHeaders.NextSibling.SelectSingleNode("./df:TablixCells", mgr);
rowHeaders = rowHeaders.SelectSingleNode("./df:TablixCells", mgr);
XmlNode sampleCol = tablixCols.SelectSingleNode("./df:TablixColumn", mgr);
XmlNode sampleHeader = rowHeaders.SelectSingleNode("./df:TablixCell", mgr);
XmlNode sampleValue = rowValues.SelectSingleNode("./df:TablixCell", mgr);
//Iterate through the column definitions and add nodes to the xml to support the columns
foreach (KeyValuePair<string,string> column in Columns)
{
//clone the sample nodes into new nodes
XmlNode newDataField = dataField.CloneNode(true);
newDataField.SelectSingleNode("./df:DataField", mgr).InnerText = column.Key;
newDataField.Attributes["Name"].Value = column.Key;
dataField.ParentNode.AppendChild(newDataField);
XmlNode newCol = sampleCol.CloneNode(true);
XmlNode newHeader = sampleHeader.CloneNode(true);
XmlNode newValue = sampleValue.CloneNode(true);
//update the new nodes with the column data
newHeader.SelectSingleNode("./df:CellContents/df:Textbox", mgr).Attributes["Name"].Value = "Header" + column.Key;
newValue.SelectSingleNode("./df:CellContents/df:Textbox", mgr).Attributes["Name"].Value = "Value" + column.Key;
//because I use friendly column names - modify the report output to use the friendly name as the display value
newHeader.SelectSingleNode("./df:CellContents/df:Textbox/df:Paragraphs/df:Paragraph/df:TextRuns/df:TextRun/df:Value", mgr).InnerText = column.Value;
newValue.SelectSingleNode("./df:CellContents/df:Textbox/df:Paragraphs/df:Paragraph/df:TextRuns/df:TextRun/df:Value", mgr).InnerText = string.Format("=Fields!{0}.Value", column.Key);
//add the new nodes to the document
tablixCols.AppendChild(newCol);
rowHeaders.AppendChild(newHeader);
rowValues.AppendChild(newValue);
tablixMember.ParentNode.AppendChild(tablixMember.CloneNode(true));
}
//remove the nodes used for cloning
objXmlDocument.SelectSingleNode("/df:Report/df:DataSets/df:DataSet/df:Fields", mgr).RemoveChild(dataField);
objXmlDocument.SelectSingleNode("/df:Report/df:Body/df:ReportItems/df:Tablix/df:TablixColumnHierarchy/df:TablixMembers", mgr).RemoveChild(tablixMember);
tablixCols.RemoveChild(sampleCol);
rowHeaders.RemoveChild(sampleHeader);
rowValues.RemoveChild(sampleValue);
//return the completed report definition
return objXmlDocument;
}
非常感谢这篇文章,旨在使我指出正确的方向.
Many thanks to this article for getting me pointed in the right direction.
这篇关于无法在ReportViewer aspx.net中显示数据表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!