【问题标题】:Sorting and paging in SSRS report viewer in MVC3 application not workingMVC3 应用程序中 SSRS 报告查看器中的排序和分页不起作用
【发布时间】:2013-04-28 15:25:04
【问题描述】:

我正在使用我的“ReportViewer”视图中的@Html.Partial 调用的 ascx 控件将 SSRS 报告集成到我的 MVC 应用程序中。

在 ascx 中我有 SSRS ReportViewer 控件,在页面加载方法中我使用模型传入的数据来设置 ReportViewer 的属性,例如 ReportPath 等。

报表呈现正常,但列排序和分页等交互功能不起作用。报告似乎正在刷新,但显示的数据保持不变。当我在报表管理器中执行报表时,排序和分页工作正常,但在我的应用程序中却不行。

这是我的 ascx:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<FEMTSWeb.Application.ViewModels.ReportViewerViewModel>" %>
<%@ Register Assembly="Microsoft.ReportViewer.WebForms, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" Namespace="Microsoft.Reporting.WebForms" TagPrefix="rsweb" %>

<script runat="server">
    private void Page_Init(object sender, System.EventArgs e)
    {
        Context.Handler = this.Page;
    }
    private void Page_Load(object sender, EventArgs e)
    {
        if (!Page.IsPostBack)
        {
            ReportViewer1.ServerReport.ReportServerUrl = new Uri(ConfigurationManager.AppSettings["ReportServerUri"]);
            ReportViewer1.ServerReport.DisplayName = Model.DisplayName;
            ReportViewer1.ServerReport.ReportPath = Model.ReportPath;
            ReportViewer1.AsyncRendering = false;
            ReportViewer1.KeepSessionAlive = false;
            ReportViewer1.ServerReport.Refresh();
        }
    }

</script>

  <form runat="server" id="frmReportViewer">
        <asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
        <div style="border-style:solid;">

            <rsweb:ReportViewer ID="ReportViewer1" runat="server" Visible="true" Width="100%" Height="100%" 
                AsyncRendering="false" 
                ProcessingMode="Remote" 
                SizeToReportContent="true"
                InteractivityPostBackMode="AlwaysAsynchronous"
            />
        </div>
   </form>

这是我调用 ascx 的视图:

@model FEMTSWeb.Application.ViewModels.ReportViewerViewModel

@{
    ViewBag.Title = "ReportViewer";
}

<h2>Report Viewer</h2>

@Html.Partial("_ReportViewer", model: (FEMTSWeb.Application.ViewModels.ReportViewerViewModel)ViewData["ReportViewerModel"])

【问题讨论】:

  • 我想知道这是否是因为回发在这种环境下不起作用。在此处尝试 iframe 方法:stackoverflow.com/questions/6144513/…
  • 回发确实有效。使用 Firebug,我发现请求中有一个错误:“Sys.WebForms.PageRequestManagerParserErrorException:无法解析从服务器收到的消息。”我检查了 POST 消息,但没有发现问题出在哪里。
  • 有趣的是,所有的报表控件(分页、刷新、排序)都存在这个问题,但我可以毫无错误地导出。
  • 您将不得不手动分页。如果您希望我知道同步解决方案和伪异步解决方案(使用 iframe),我可以提供进一步帮助。但至于在 MVC 中工作的分页,除非你做一些工作,否则它不会。排序,如果您正在谈论交互式排序,除非您找到类似的解决方法,否则很可能不会起作用。我目前只是在将数据发送到 ReportViewer 控件之前对其进行排序。
  • 您是否尝试过上面链接中的 iframe 方法?

标签: asp.net-mvc-3 reporting-services reportviewer


【解决方案1】:

ReportViewer是一个需要viewstate的控件,MVC没有。 要进行分页,您有两个选择, 1.在session中保留当前页面,使用ajax保留当前页面。 2.在页面上保留一个隐藏的iframe,使用jquery刷新,然后用iframe的内容替换页面。这给人一种伪异步的感觉。

关于 #1 的注释,ReportViewer 在呈现报告(页面加载后)之前不会确定总页数,因此您最好的办法是在页面加载时抓取它并告诉会话它是什么,以便您可以更好地浏览您的报告。

**

  • #1 示例:

** ReportViewerControl.ascx - 包含 ReportViewer 控件的部分视图。

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<NMBS.Models.SelectedReport>" %>
<%@ Register Assembly="Microsoft.ReportViewer.WebForms, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" Namespace="Microsoft.Reporting.WebForms" TagPrefix="rsweb" %>
<form id="Form1" runat="server">
    <asp:ScriptManager ID="ScriptManager1" runat="server" />
    <rsweb:ReportViewer ID="ReportViewer" runat="server" Width="652px" AsyncRendering="false">
    </rsweb:ReportViewer>
</form>
<script runat="server">
    /* Prepare the ReportViewer Control to be Displayed */
    private void Page_Load(object sender, System.EventArgs e)
    {    
        // Set the PageCount Mode to Actual (Exact) instead of the Default (Approx.)
        ReportViewer.PageCountMode = PageCountMode.Actual;

        // Load Report Definition.
        // Load DataSets.
        // Etc...

        ReportViewer.CurrentPage = Convert.ToInt32(Session["CurrentPage"]);
        ReportViewer.LocalReport.Refresh();
    }
</script>

ReportView.cshtml - 将显示 ReportViewer Partial 的 Razor 视图。

@* ReportViewer Control *@
<div id="div-report"> 
    @* Load the Report Viewer *@
    @Html.Partial("ReportViewerControl", this.ViewData.Model) <br />
</div>

@* Scripts *@
<script type="text/javascript" src="/Scripts/jquery-1.9.1.min.js"></script>
<script type="text/javascript" src="/Scripts/Json2.js"></script>
<script type="text/javascript" src="/Scripts/ReportView-Scripts.js"></script>

ReportView-Scripts - 用于加载 ReportViewer 和适当导航的脚本。

// Since the ReportViewer Control determines the PageCount at render time, we must
//  send back the Total Page Count for us to use later.
function SetTotalPages() {
    var CurrentPage = $("#Form1 > span > div > table > tbody > tr:eq(2) > td > div > div > div:eq(0) > table > tbody > tr > td:eq(4) > input").val(),
        PageCount =  $("#Form1 > span > div > table > tbody > tr:eq(2) > td > div > div > div:eq(0) > table > tbody > tr > td:eq(8) > span").html();

    // Send JSON to /Report/SetPageCount/.
    // /Report/SetPageCount/ this action sets the variable Session["PageCount"] equal to the variable passed to it.
    $.ajax({
        url:"/Report/SetPageCount/",
        type: "POST",
        dataType: "json",
        data: "{ Count:" + PageCount + "}",
        cache: false,
        contentType: 'application/json; charset=utf-8',
        success: function (response, textStatus, jqXHR) 
        { },
        error: function (jqXHR, textStatus, errorThrown) 
        { }
    });

    // When done, update the Information.
    $("#txtNavigation").val(CurrentPage.toString() + " of " + PageCount.toString());

    // Don't do unnecessary Ajax Calls.
    //  If the Report is already on the First page, don't try navigating to Previous or First.
    Nav.UpdateFunctionality();
}

var Nav = {
    // If passed true, Enables First and Previous buttons.
    // If passed false, Disables them.
    ToggleFirstPrev: function ToggleFirstPrevNav(Toggle) {
        var NavBar = $("#span-navigation");
        if (Toggle == true) {
            // Enable First and Previous.
            NavBar.children("input[title=First]").removeAttr("disabled");
            NavBar.children("input[title=Previous]").removeAttr("disabled");

        } else {
            // Disable First and Previous.
            NavBar.children("input[title=First]").attr("disabled", true);
            NavBar.children("input[title=Previous]").attr("disabled", true);
        }
    },
    ToggleLastNext: function ToggleLastNextNav(Toggle) {
        var NavBar = $("#span-navigation");
        if (Toggle == true) {
            // Enable First and Previous.
            NavBar.children("input[title=Last]").removeAttr("disabled");
            NavBar.children("input[title=Next]").removeAttr("disabled");

        } else {
            // Disable First and Previous.
            NavBar.children("input[title=Last]").attr("disabled", true);
            NavBar.children("input[title=Next]").attr("disabled", true);
        }
    },
    UpdateFunctionality: function UpdateNavBarFunctionaility() {
        var CurrentPage = $("#Form1 > span > div > table > tbody > tr:eq(2) > td > div > div > div:eq(0) > table > tbody > tr > td:eq(4) > input").val(),
            PageCount = $("#Form1 > span > div > table > tbody > tr:eq(2) > td > div > div > div:eq(0) > table > tbody > tr > td:eq(8) > span").html(),
            Navi = Nav;

        // Don't do unnecessary Ajax Calls.
        //  If the Report is already on the First page, don't try navigating to Previous or First.
        if (parseInt(CurrentPage, 10) <= 1) {
            Navi.ToggleFirstPrev(false);

        } else {
            Navi.ToggleFirstPrev(true);
        }

        // If the Report is already on the Last page, don't try navigating to Next or Last.
        if (parseInt(CurrentPage, 10) >= parseInt(PageCount, 10)) {
            Navi.ToggleLastNext(false);
        } else {
            Navi.ToggleLastNext(true);
        }
    }
};

// Makes an Ajax call telling the Action (NavReportControl) which navigation button was clicked.
//  It then on the Server-Side updates the CurrentPage Counter to the New Page (based on Nav Button Clicked).
//  On Success it Refreshes the Iframe. On Iframe Load it copies over the new ReportViewer Control.
//  (Reason we do it this way is because without the IFrame we'd have to do it synchronously to get the
//   ReportViewer Control to do it's Initialize Function).
function NavReport(e) {
    // Gets what Navigation Action the user is trying to accomplish. (Next, Previous, First, Last) (and also Apply but that'll Change)
    var Navi = { Nav: $(this).val() },
        CurrentPage = $("#Form1 > span > div > table > tbody > tr:eq(2) > td > div > div > div:eq(0) > table > tbody > tr > td:eq(4) > input").val(),
        PageCount = $("#Form1 > span > div > table > tbody > tr:eq(2) > td > div > div > div:eq(0) > table > tbody > tr > td:eq(8) > span").html();

    // Get the New ReportViewer Control.
    $.ajax({
        type: "GET",
        dataType: "json",
        data: Navi,
        cache: false,
        contentType: 'application/json; charset=utf-8',
        url: "/Report/NavReportControl", 
        success: function () {
            RefreshiFrame();
        }
    });
}

**

  • #2 示例:

**

// Refreshes the Iframe containing another instance of the ReportViewer Control.
function RefreshiFrame() {
    // Hide the Report till update is finished.
    $("#div-report").fadeOut(175);

    // Refresh the Hidden Frame on the Page.
    document.getElementById("iframe1").contentDocument.location.reload(true);
}

// This function is ran when the iFrame is finished loading.
//   SrcName - Name of the Source iFrame. Ex. "#iframe1"
//   DestName - Name of the Destination Div Ex. "#div-report"
function RefreshReport(SrcName, DestName) {
    // Copy its "div-report" and CSS then replace it with the actual pages after reload.
    var ReportViewer = $(SrcName).contents().find(DestName).html(),
        CSS = $(SrcName).contents().find("head").children("[id*='ReportViewer']").clone(),
        CurrentPage, 
        PageCount;

    // Report Current ReportViewer with new ReportViewer.
    $(DestName).html(ReportViewer);

    //Add the New CSS to your current page.
    $("head").append(CSS);

    // Make sure the Report is visible.
    $("#div-report").show();

    // Update Nav Functionality.
    // Don't do unnecessary Ajax Calls.
    //  If the Report is already on the First page, don't try navigating to Previous or First.
    Nav.UpdateFunctionality();
}

【讨论】:

    【解决方案2】:

    仅使用以下链接中的 reportViewerExample 文件夹,

    https://github.com/ilich/MvcReportViewer

    使用在线 nuget 包安装缺少的引用。在 web.config 中配置您的服务器路径、凭据(安装查看器后,在 web.config 中已经创建了相关密钥),也在视图 Index.chtml 中进行了适当的更改

    它适用于所有导航控件,无需重新加载页面。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-12-08
      • 2017-11-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多