无法在ReportViewer aspx.net中显示DataTable

时间:2015-04-21 17:05:06

标签: c# asp.net datatable report reportviewer

我无法在ReportViewer控件中显示DataTable对象的内容。没有错误,只有页面上显示空白的报表查看器。我查看了在hereherehere发现的各种类似问题中提出的解决方案 - 最后一个问题特别令人沮丧,因为最后一条评论说“让我们在聊天中继续讨论”没有提供答案,这基本上是我的确切问题。

网页代码:

    <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数据属性似乎也有数据 - 它只是没有显示....

非常感谢任何帮助!

1 个答案:

答案 0 :(得分:0)

因此,在经过大量研究和谷歌搜索以及来自我的优秀开发同事的帮助后,我遇到了一个解决方案,主要涉及重建.rdlc文件的xml结构以支持动态列。这种方法有几点需要注意。 1.您必须手动配置引用数据源的xml以指向提供数据表的对象方法,因为报表设计器不支持此操作。我在下面包含了我的xml更改。 2.您必须在报表定义中添加一个表,其中只有一列和一行。也许有人可以做得更好。

所以解决方案。首先是rdlc xml数据源配置:

<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>

接下来,您必须配置报表查看器以从内存流中接收报表定义:

            //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();

最后我有这个方法,这是我在研究问题时发现的其他几种方法的修改版本

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;
    }

非常感谢this文章让我指出了正确的方向。