ReportViewer is a control that needs viewstate, which MVC does not have.
To do Paging, you have two choices,
1. Keep your current page in the session and use ajax to keep the current page.
2. Keep a hidden iframe on the page, use jquery to refresh it, then replace the page with the iframe's contents. This gives a pseudo-asynchronous feel.
A note on #1, ReportViewer does not determine total page count until the report is rendered (after page loads), therefore your best bet is to grab it on pageload and tell the session what it is so you can better navigate your report.
**
**
ReportViewerControl.ascx - Partial View containing 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 - Razor View that will display the ReportViewer Partial.
@* 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 - Scripts to load ReportViewer and Navigate appropriately.
// 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();
}
});
}
**
**
// 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();
}