MVC3应用程序中的SSRS报表查看器中的排序和分页不起作用

时间:2013-04-28 15:25:05

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

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

在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"])

2 个答案:

答案 0 :(得分:0)

ReportViewer是一个需要viewstate的控件,MVC没有。 要做分页,你有两个选择, 1.将当前页面保留在会话中并使用ajax保留当前页面。 2.在页面上保留一个隐藏的iframe,使用jquery刷新它,然后用iframe的内容替换页面。这给出了伪异步的感觉。

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

**

  • #1的例子:

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

<%@ 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 View。

@* 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();
}

答案 1 :(得分:0)

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

https://github.com/ilich/MvcReportViewer

使用在线nuget软件包安装缺少的引用。在web.config中配置服务器路径,凭证(安装查看器后已在web.config中创建相关密钥),以及视图中的相应更改Index.chtml

它可以正常使用所有导航控件,无需重新加载页面。