Wednesday, 9 March 2011

Printing Multi Page GridView with Preview - 2



As discussed in previous post, this post concentrates on how to print the GridView contents using Javascript when it has multiple pages exists.

I am connecting to the Northwind database for this example.

The following implementation shows the second method to preview all the records in the GridView using Javascript.

In aspx script.
<div id="GridViewContent">
    <asp:GridView ID="grdViewProducts" runat="server" 
        AllowPaging="True" AutoGenerateColumns="False" TabIndex="1"
        DataKeyNames="ProductID" Width="100%" CssClass="GridViewStyle"
        ShowFooter="false" CellPadding="4" ForeColor="#333333" GridLines="None" 
        OnPageIndexChanging="grdViewProducts_PageIndexChanging">
        <RowStyle BackColor="#F7F6F3" ForeColor="#333333" />
        <Columns>
            <asp:BoundField DataField="ProductID" HeaderText="Product ID" />
            <asp:BoundField DataField="ProductName" HeaderText="Product Name" />
            <asp:BoundField DataField="CompanyName" HeaderText="Supplier" />
            <asp:BoundField DataField="CategoryName" HeaderText="Category" />
            <asp:BoundField DataField="QuantityPerUnit" 
                                    HeaderText="Quantity Per Unit" />
            <asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice" />
        </Columns>
        <FooterStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
        <PagerStyle BackColor="#284775" ForeColor="White" HorizontalAlign="Center" />
        <SelectedRowStyle BackColor="#E2DED6" Font-Bold="True" ForeColor="#333333" />
        <HeaderStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
        <EditRowStyle BackColor="#999999" />
        <AlternatingRowStyle BackColor="White" ForeColor="#284775" />
    </asp:GridView>
    <asp:Button Text="Print" runat="server" ID="btnPrint" onclick="btnPrint_Click" />
    <asp:HiddenField ID="hndGridViewPrintContent" runat="server" />
    
    <asp:Button Text="For Checking Postback" runat="server" ID="Button1" />
    <asp:DropDownList runat="server" ID="DDLPostBack" AutoPostBack="true"
        onselectedindexchanged="DDLPostBack_SelectedIndexChanged">
        <asp:ListItem Text="List 1" Value="List 1"></asp:ListItem>
        <asp:ListItem Text="List 2" Value="List 2"></asp:ListItem>
    </asp:DropDownList>
</div>
This javascript may thro’ an error (You can only have one <title> element within the <head> element.) if you keep it in the Page header. Because it contains <title> in the Javascript script. So you can place it inside of the body itself or remove any one <title> from the Javascript or Page.
function PrintGridView() {
    var printWindow = window.open("", "mywindow", "location=0,status=0,scrollbars=1,resizable=1");
    var strContent = "<html><body>";
    strContent = strContent + "<title>Print Preview</title>";
    strContent = strContent + "<link href=\"App_Themes/Default/Default.css\" type=\"text/css\" rel=\"stylesheet\" />";
    strContent = strContent + "</head><body>";
    strContent = strContent + "<div id='buttons' style='width:100%;text-align:right;'>";
    strContent = strContent + "<input type='button' id='btnPrint' value='Print' style='width:100px' onclick='window.print()' />";
    strContent = strContent + "<input type='button' id='btnCancel' value='Cancel' style='width:100px' onclick='window.close()' />";
    strContent = strContent + "</div>";
    strContent = strContent + "<div style='width:100%;'>";
    strContent = strContent + document.getElementById('<%= hndGridViewPrintContent.ClientID %>').value;
    strContent = strContent + "</div>";
    strContent = strContent + "</body>";
    printWindow.document.write(strContent);
    printWindow.document.close();
    printWindow.focus();
    document.getElementById('<%= hndGridViewPrintContent.ClientID %>').value = '';
}
.GridViewStyle
{
    font-family:Calibri;
    font-size:12px;
}
protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        BindGrid();
    }
}
private void BindGrid()
{
    using (SqlConnection connection =
        new SqlConnection(ConfigurationManager.ConnectionStrings
                            ["SQLConnection"].ConnectionString))
    {

        SqlCommand command = new SqlCommand(
               "SELECT ProductID, ProductName, CompanyName, CategoryName, " +
               "QuantityPerUnit, UnitPrice FROM Products " +
               "JOIN Suppliers ON Products.SupplierID = Suppliers.SupplierID " +
               "JOIN Categories ON Products.CategoryID = Categories.CategoryID " +
               "Order by ProductID", connection);

        connection.Open();
        SqlDataReader dr = command.ExecuteReader(CommandBehavior.CloseConnection);

        IList<ProductView> productViewList = new List<ProductView>();
        while (dr.Read())
        {
            ProductView productView = new ProductView();
            productView.ProductID = dr["ProductID"].ToString();
            productView.ProductName = dr["ProductName"].ToString();
            productView.CompanyName = dr["CompanyName"].ToString();
            productView.CategoryName = dr["CategoryName"].ToString();
            productView.QuantityPerUnit = dr["QuantityPerUnit"].ToString();
            productView.UnitPrice = Convert.ToDouble(dr["UnitPrice"].ToString());
            productViewList.Add(productView);
        }
        grdViewProducts.DataSource = productViewList;
        grdViewProducts.DataBind();
    }
}
protected void grdViewProducts_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
    grdViewProducts.PageIndex = e.NewPageIndex;
    BindGrid();
}
protected void btnPrint_Click(object sender, EventArgs e)
{
    grdViewProducts.AllowPaging = false;
    BindGrid();
    System.IO.StringWriter stringwriter = new System.IO.StringWriter();
    System.Web.UI.HtmlTextWriter htmlwriter = new System.Web.UI.HtmlTextWriter(stringwriter);
    grdViewProducts.RenderControl(htmlwriter);
    hndGridViewPrintContent.Value = stringwriter.ToString();

    Page.RegisterStartupScript("Print", "<script type=\"text/javascript\">" +
    "PrintGridView();</" + "script>");

    grdViewProducts.AllowPaging = true;
    BindGrid();
}
/// <summary>
/// This event is used to remove the error occuring while exporting to export
/// The Error is : Control 'ControlID' of type 'GridView' must be placed inside a form tag with runat=server.
/// </summary>
/// <param name="control"></param>
public override void VerifyRenderingInServerForm(Control control)
{
    return;
}

protected void DDLPostBack_SelectedIndexChanged(object sender, EventArgs e)
{
}
public class ProductView
{
    public string ProductID { get; set; }
    public string ProductName { get; set; }
    public string CompanyName { get; set; }
    public string CategoryName { get; set; }
    public string QuantityPerUnit { get; set; }
    public double UnitPrice { get; set; }
}
Considering the implementation point of view both (previous and this post) are almost same. The idea behind is, we are declaring a hidden control in the page. When the user clicks the Print button, the click event on the code behind which binds all the records to the GridView, get the HTML code and assigning to the hidden control. Then it also calls a PrintGridView() javascript function from code behind using RegisterStartupScript method. So once the runtime loads the page, it will calls the javascript function PrintGridView() and preview the GridView content using the hidden control added on the page.

I have added some other controls like Button, DropDown box for verifying page result when post back happening. So make sure you declared false for ValidateRequest. on the page

This method will be useful when there are large no of records required to bind to the grid and gets the content. Because, it will be done only when the user require to preview (print) the content by clicking the Print button. But one issue is, as the code behind inject a Javascript code to call PrintGridView() function once page loaded, if the user refresh the page (using F5, Refresh button) it will call again the same method and shows the preview.

The output of the implementation would be :
GridView with Multi page

Preview window with all records

download the source code here


2 Responses to “Printing Multi Page GridView with Preview - 2”

  • anupganatra says:
    28 October 2012 at 19:52

    Hello your code is very useful and running fine but in mozilla and google chrome I am getting following error
    A potentially dangerous Request.Form value was detected from the client (ctl00$ContentPlaceHolder1$hndGridViewPrintContent="div
    <table cells...").
    Description: Request Validation has detected a potentially dangerous client input value, and processing of the request has been aborted. This value may indicate an attempt to compromise the security of your application, such as a cross-site scripting attack. You can disable request validation by setting validateRequest=false in the Page directive or in the configuration section. However, it is strongly recommended that your application explicitly check all inputs in this case.

    Exception Details: System.Web.HttpRequestValidationException: A potentially dangerous Request.Form value was detected from the client (ctl00$ContentPlaceHolder1$hndGridViewPrintContent="<div>
    <table cells...").

    Source Error:


    [No relevant source lines]


    Source File: c:\Users\Anup\AppData\Local\Temp\Temporary ASP.NET Files\citizeninfo_test\0582e655\f1782b60\App_Web_te2tvksk.10.cs Line: 0

    Stack Trace:


    [HttpRequestValidationException (0x80004005): A potentially dangerous Request.Form value was detected from the client (ctl00$ContentPlaceHolder1$hndGridViewPrintContent="<div>
    <table cells...").]
    System.Web.HttpRequest.ValidateString(String s, String valueName, String collectionName) +8723434
    System.Web.HttpRequest.ValidateNameValueCollection(NameValueCollection nvc, String collectionName) +111
    System.Web.HttpRequest.get_Form() +129
    System.Web.HttpRequest.get_HasForm() +8723543
    System.Web.UI.Page.GetCollectionBasedOnMethod(Boolean dontReturnNull) +97
    System.Web.UI.Page.DeterminePostBackMode() +63
    System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +6785
    System.Web.UI.Page.ProcessRequest(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +242
    System.Web.UI.Page.ProcessRequest() +80
    System.Web.UI.Page.ProcessRequestWithNoAssert(HttpContext context) +21
    System.Web.UI.Page.ProcessRequest(HttpContext context) +49
    ASP.default2_aspx.ProcessRequest(HttpContext context) in c:\Users\Anup\AppData\Local\Temp\Temporary ASP.NET Files\citizeninfo_test\0582e655\f1782b60\App_Web_te2tvksk.10.cs:0
    System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +181
    System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +75




    --------------------------------------------------------------------------------
    Version Information: Microsoft .NET Framework Version:2.0.50727.4927; ASP.NET Version:2.0.50727.4927

  • Thiru says:
    29 October 2012 at 12:58

    Hi Anupganatra,

    Just add the below line at the end of the PrintGridView() function in javascript. It must work fine.

    document.getElementById('<%= hndGridViewPrintContent.ClientID %>').value = '';

    I tested in firefox, it works fine now.

Post a Comment