Sunday, November 15, 2009

SQL Server Report Viewer Autosize

In Visual Studio, report viewer control for web is used control for displaying Microsoft SQL Server Reporting Services reports on an ASP.NET page. When the report viewer control is dropped on a web page, it will be displayed in the default size; width:400px and height:400px. That will not fit for most of the live reports.




We can set the width of the report viewer control to 100% or to a desired size, because the width of the report won't change dynamically. if the width is specified as 100%, that means the report viewer should fit to 100% of the browser width. If the report's width exceeds the browsers width, scroll bar will be displayed inside the report viewer control. Setting the height property to 100% will not work and we are not able to predict how many records will come on a single page (that is the required height of the report viewer control). So this will bring a horizontal scroll bar inside the report viewer control. This is not the expected behavior of a report page normally. If the report exceeds the width and height of the browser, the scroll bars should come inside the browser.



So what is the solution? Either report viewer should resize automatically to fit the content or we have to set the size of the report viewer dynamically.

Report Viewer control has a property FitToContent. The description of this property says it will expand/shrink according to the report content. However it will work only with another property AsyncRendering. This should be true.

When I worked with report viewer and experienced the same situation, I tried to use the above properties. Unfortunately a host of javscript errors prevented me to use these properties for my purpose. I searched all over the internet for a solution. But nothing solved my issue. So I started to investigate. I knew that writing some javascript to dynamically set the size of the report control is the solution to the problem. But how do I know the size of the report content? That was the big issue.

I examined the client side source of the page after the report is rendered. I scratched my head for some days to find the following information. Report viewer uses a number of iframes and divs to display reports. Report viewer itself is a div with id as same as the report viewer control. So setting the height & width to this div will set the size of the report. Again, reporting services report has two sections. The first one displays the input fields (parameters) and the view report button. The second part is the actual report. The next part of the investigation was to find the container of the report. It was not an easy task, because the report viewer control generates a lot of script on client side. This container is an iframe with id "ReportFrame" + ReportViewer1.ClientID. Here ReportViewer1 is the name of the report viewer control. But that was not the end of the research. This control again contained other containers. Finally I found that one div with id="oReportDiv" is the actual report container and it has the actual width and height. Then I had to establish the relation between the report frame and the report div. After hours of experiments the relation evolved as
div=reportFrame.document.getElementById("report").contentDocument.getElementById("oReportDiv").

Okay, now I have to implement this in the onload event. The resultant script was a very simple script as follows.

window.onload=function()
{
var viewer = document.getElementById("ReportViewer1");
var frame = document.getElementById("ReportFrame<%=ReportViewer1.ClientID %>");
if (frame != null && viewer != null)
{
var reportDiv = eval("ReportFrame<%=ReportViewer1.ClientID %>").document.getElementById("report").contentDocument.getElementById("oReportDiv");
viewer.style.height = reportDiv.scrollHeight;
viewer.style.width = reportDiv.scrollWidth;
}

}


And this solved my issue.