ASP.NET download PDF feature in UpdatePanel unable to refresh UpdateProgress control

256 Views Asked by At

I've two UpdatePanel in a page. The second one has UpdateMode="Conditional" and here there's a link button to produce PDF file. My goal is to allow the PDF download and in the meantime make a waiting image appear (like an hourglass). After a few days of studying I reached my goal but i can't hide the image after all operations are terminated.

In the code example i've simplified logic to procude pdf (in complete code i use gridview control data to produce pdf).

  1. If I use an asynchronous PostBackTrigger in UpdatePanel the PDF is not downloaded even if the UpdateProgress (with the expected image) works correctly.

  2. If I use a Synchronous PostBackTrigger in UpdatePanel the PDF is downloaded correctly but the updateProgress does not work because the waiting image remains on the screen. In this case i've used a client side function (postbackButtonClick) to display the image.

I've read many threads but each one is always a little different.

My actual goal is to know if possible on client side when the PDF production operation is complete to hide the image.

Maybe the general approach is wrong?

aspx file

<body>
<form id="form1" runat="server">
<div>

    <asp:ScriptManager runat="server" EnableCdn="true">  </asp:ScriptManager>

    <asp:UpdateProgress ID="UpdateProgress1" DynamicLayout="true" runat="server" AssociatedUpdatePanelID="updateGrid" DisplayAfter="0" >
         <ProgressTemplate> <div class="progress"> <img src="../images/ajax-loader.gif" />&nbsp;Waiting...</div>                                                               </ProgressTemplate>
    </asp:UpdateProgress>

    <asp:UpdatePanel ID="updateGrid" runat="server">
        <ContentTemplate>
         <asp:TextBox class='form-control' ID="txtMat" runat="server" style='width:110px' Text="1672"></asp:TextBox>
         <asp:Button class='btn btn-primary' ID="cmdGO" runat="server" Text="Execute"/>
       </ContentTemplate>
    </asp:UpdatePanel>

    <asp:UpdatePanel ID="UpdatePanel2" runat="server" UpdateMode="Conditional">
         <ContentTemplate>
                <asp:Panel ID="panelCMD" runat="server">
                      <asp:LinkButton ID="LinkButton3" OnClientClick="return postbackButtonClick();"
                                      runat ="server" CssClass="btn btn-small btn-primary fullwidth" OnClick="mtdCreatePDF"><i class="icon icon-ok"></i>&nbsp;TEST PDF</asp:LinkButton>
                       </asp:Panel>
         </ContentTemplate>
         <Triggers >
             <asp:PostBackTrigger ControlID="LinkButton3"   />
        </Triggers>
 </asp:UpdatePanel>

     <asp:UpdateProgress ID="UpdateProgress2" ClientIDMode="Static" DynamicLayout="true" runat="server"  AssociatedUpdatePanelID="UpdatePanel2" DisplayAfter="0" >
     <ProgressTemplate>
     <div class="progress">
     <asp:image id="imgOld" runat="server" imageurl="../images/ajax-loader.gif" />
     <br />
     <img id="imgLike" src="../images/ajax-loader.gif" />&nbsp;Attendere...</div>
     </ProgressTemplate>
     </asp:UpdateProgress>


</div>
</form>
<script src="Test.js" type="text/javascript"></script>

Test.js

function postbackButtonClick() {
updateProgress = $find("UpdateProgress2");
window.setTimeout(function () { updateProgress.set_visible(true); }, 100);
return true;

}

cs file

 protected void mtdCreatePDF(object sender, EventArgs e)
    {

        byte[] content = null;
        string TypeOutput = "RESPONSE";
        string suffix = @"Pdf_PROD\Print.pdf";
        string nameTGT = HttpContext.Current.Server.MapPath("~") + suffix;
        var stream = new MemoryStream();
        var writer = new PdfWriter(stream);
        var pdf = new PdfDocument(writer);
        var document = new Document(pdf);
        document.Add(new Paragraph("Hello world!"));
        document.Close();

        if (TypeOutput == "RESPONSE")
        {
            Response.Clear();
            Response.ClearContent();
            Response.ClearHeaders();
            Response.ContentType = "application/pdf";
            Response.AddHeader("content-disposition", "attachment;filename=print.pdf");
            Response.Cache.SetCacheability(HttpCacheability.NoCache);
            //writer.SetCloseStream(false);
            Response.BinaryWrite(stream.ToArray());
            Response.End();
        }

        else
        {
            content = stream.ToArray();
            using (FileStream fs = File.Create(nameTGT))
            {
                fs.Write(content, 0, (int)content.Length);
            }
        }


    }
2

There are 2 best solutions below

1
On BEST ANSWER

First, there needs to be a timeoutID for the timeout. We will use it later to disable the timeout. After pdf creation is completed, hideUpdateProgress() function will be called from code-behind to hide the progress image.

Test.js

var timeoutID;

function postbackButtonClick() {
updateProgress = $find("UpdateProgress2");
timeoutID = window.setTimeout(function () { updateProgress.set_visible(true); }, 100);
return true;

function hideUpdateProgress()
{
    clearTimeout(timeoutID);
    updateProgress = $find("UpdateProgress2");
    updateProgress.set_visible(false);
}

To call hideUpdateProgress();, you can add this line at the end of mtdCreatePDF function.

ClientScript.RegisterStartupScript(Page.GetType(), 
    "hideUpdateProgress",
    "hideUpdateProgress();",
    true);
0
On

I solved it in the following way: I moved everything to the client side.

A. I added a client-side event on the click of the link button

<asp:LinkButton ID="LinkButton6" OnClientClick="return TestPDFDEF();" runat="server" CssClass="btn btn-small btn-primary fullwidth"><i class="icon icon-ok"></i>&nbsp;TEST PDF WebService Def</asp:LinkButton>

B. I added a WebMethod to the page that provides a variable of type [byte] to the Ajax call

[WebMethod]
        [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
        public byte[] GetPDF(List<Classes.GridCosts> MyGrid)
{

     foreach (Classes.GridCosts rowsGrid in GrMyGridglia)
        {
            Console.Write(rowsGrid.Field1);
            Console.Write(rowsGrid.Field2);

        }

   string suffix = @"Pdf_PRODOTTI\Print.pdf";
   string nameTGT = HttpContext.Current.Server.MapPath("~") + suffix;
   var stream = new MemoryStream();
   var writer = new PdfWriter(stream);
   var pdf = new PdfDocument(writer);
   var document = new Document(pdf);
   document.Add(new Paragraph("Hello world!"));
   document.Close();

   return stream.ToArray();
 }

C. I have defined a class for receiving the grid that will be passed to the method

 public class GridCosts 
{
        public string Field1{ get; set; }
        public string Field2{ get; set; }
}

D. Added image that appears for hourglass:

$(document).ready(function () {

$('body').append('<div class="progress" id="ajaxBusy"><p><img src="../images/ajax-loader.gif">&nbsp;Waiting..</p></div>');
$('#ajaxBusy').hide();

//$('#ajaxBusy').css({
//    display: "none",
//    left: "50%",
//    margin: "0px",
//    paddingLeft: "0px",
//    paddingRight: "0px",
//    paddingTop: "0px",
//    paddingBottom: "0px",
//    position: "fixed",
//    right: "3px",
//    top: "35%",
//    width: "auto"
//});

// Ajax activity indicator bound to ajax start/stop document events
$(document).ajaxStart(function () {
    $('#ajaxBusy').show();
}).ajaxStop(function () {
    $('#ajaxBusy').hide();
});

});

E. I sent the variable referred to in point B to the user with Javascript

function TestPDFDEF() {
$(function () {

    var MyGrid= new Array();

    var CostsRow = {};
    $('[id*=MyGrid]').find('tr:has(td)').each(function () {
        CostsRow.Field1= $.trim($(this).find("td:nth-child(3)").text());
        CostsRow.Field2= $.trim($(this).find("td:nth-child(4)").text());
        MyGrid.push(CostsRow );
        CostsRow = {};
    });

        type: "POST",
        url: "WebService1.asmx/GetPDF",
        contentType: "application/json; charset=utf-8",
        data: '{MyGrid: ' + JSON.stringify(MyGrid) + '}',
        dataType: "json",
        beforeSend: function () {
        },
        success: function (data) {
            data = data.d;
            var byteArray = new Uint8Array(data);
            var a = window.document.createElement('a');
            a.href = window.URL.createObjectURL(new Blob([byteArray], { type: 'application/pdf' }));
            a.download = 'FileName';
            document.body.appendChild(a)
            a.click();
            document.body.removeChild(a)

        },
        complete: function (data) {
            
        },
        error: function (XMLHttpRequest, textStatus, errorThrown) {
            
            alert(textStatus);
        }
    });



});

}