[SOLVED] ASP.NET page for file processing, Unable to get a Loading GIF to render before procedures begin

Issue

I have a webforms app that uses a typical file downloader page accessed from many placed in my application. Under normal circumstances the page serves the file, closes and the user never even knows it exists. However, I have added a PDF conversion tool that converts certain documents to PDF and this process takes a few seconds, so the end user will see the page, and I am ok with that.

I am trying to add some simple text and a "Loading" GIF to the page, but I can’t get it to render before the page load events starts and blocks the page from rendering.

I have a simple page load event that decides what procedure to run.

Protected Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load
    If Not Me.IsPostBack Then
        Dim Type As String = Request.QueryString("Type")
        If Type = "File" Then
            'TODO
        ElseIf Type = "DB" Then
            OpenDBFile()
        ElseIf Type = "QCBDBYMCSID" Then
            OpenQCBD("BYMCSID")
        ElseIf Type = "QCBDBYNAME" Then
            OpenQCBD("BYNAME")
        Else
            'TODO
        End If
    End If
End Sub

I have tried to delay this by replacing Me.Load with an event later in the page lifecycle, like Me.SaveStateComplete and there is no change.

In the client side I tried a few different options using and update panel, an UpdateProgress and just a plain DIV using CSS to set a background image instead of an image tag, but nothing shows.

here are 2 examples of what I tried.

    <asp:UpdatePanel ID="UpdatePanel1" runat="server" >
        <ContentTemplate>
            <div style="text-align: center">
                <h1 style="text-align: center;">MCS File Downloader</h1>
                <asp:Image ID="Image2" ImageAlign="Middle" ImageUrl="~/MyPictures/colorchangearrowdown.gif" runat="server" />
                <h3 runat="server" id="h3Text" style="text-align: center">Processing File...</h3>
            </div>
        </ContentTemplate>
    </asp:UpdatePanel>


<asp:UpdateProgress ID="prgLoadingStatus" runat="server" DynamicLayout="true">
            <ProgressTemplate>
                <div id="overlay">
                    <div id="modalprogress">
                        <div id="theprogress">
                            <h1 style="text-align: center;">MCS File Downloader</h1>
                            <asp:Image ID="imgWaitIcon" runat="server" ImageAlign="AbsMiddle" ImageUrl="~/MyPictures/colorchangearrowdown.gif" />
                            <h3 runat="server" id="h3Text" style="text-align: center">Processing File...</h3>
                        </div>
                    </div>
                </div>
            </ProgressTemplate>
        </asp:UpdateProgress>

Any help would be greatly appreciated!

Solution

Well, you can’t turn off, or hide, or so ANYTHING from code behind. You click on a button, and the page gets sent to the server. Then code behind runs, and then the page is sent back down.

code behind NEVER interacts directly with the user. The page post back sends teh WHOLE page to the server. When code beind runs, it can modify controls, text box etc. However, the user sees zero of that until ALL CODE behind is done, and then the WHOLE page makes it trip back down to the client side, is re-loaded, JavaScrip re-runs, and then the page is displayed. So, mucking around with all kinds of server side code is a 100% waste of time and is a wild goose chase.

However, with a simple grasp of the page life-cycle, and post backs (the so called round trip), then some solutions become easy – in fact VERY easy here.

So, for whatever you want to do? Say click on on a button? Then add both a client side event, and a server side event.

The client side can now display the spinner (animated gif) or whatever. And in fact in 99% of cases, you don’t need ANY code to hide that spinner or whatever, since when all that server side code behind is done? Well, a whole new copy of the web page comes racing down from the server, and thus you get a re-plot and re-load of the WHOLE page for free – including that of your hidden spinner/gif now being hidden agian.

So, at the most simple level, try this code on a blank new test page:

You don’t need fancy code, you don’t need threading, you don’t need much of anything. (but you do need a simple grasp of how page post-backs work).

So, we going to drop a button on a web page. We will click on that button, and we have a long running server side button code behind (say 5 seconds). When the code behind is done, the spinner will go away.

So, we have this markup: a button, and then animated "gif" spinner:

       <div id="MySpinner" runat="server" style="display:none">
            <img src="Content/wait2.gif" />
        </div>


        <div id="MyGrid" runat="server" style="width:50%">
            <asp:GridView ID="GridView1" runat="server" CssClass="table"></asp:GridView>
        </div>

        <asp:Button ID="cmdLoadGrid" runat="server" Text="Load data" CssClass="btn"
            OnClientClick="ShowSpinner();return true;" />


    </div>

        <script>

            function ShowSpinner() {
                $("#MySpinner").show();

            }

        </script>

Note how I hide the spinner in a div (display:none).

And note how we have a plane jane button, but it ALSO has a client side click event.

The code behind is this

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

End Sub

Protected Sub cmdLoadGrid_Click(sender As Object, e As EventArgs) Handles cmdLoadGrid.Click

    Thread.Sleep(4000)       ' fake a big delay

    Dim strSQL As String = "SELECT TOP 6 ID, FirstName, LastName, HotelName, City, Description from tblHotels
                            WHERE Description is not null"

    Using conn As New SqlConnection(My.Settings.TEST4)
        Using cmdSQL As New SqlCommand(strSQL, conn)

            conn.Open()
            GridView1.DataSource = cmdSQL.ExecuteReader
            GridView1.DataBind()

        End Using
    End Using

    '' hide the spinner
    'MySpinner.Style("Display") = "none"
    'MyGrid.Style("Display") = "normal"

End Sub

So I tossed in that "fake" delay of 4 seconds.

so, the page looks like this:

enter image description here

If I click on the button, then we see this:

enter image description here

And then when server code is done, it sends back the whole page, and I now see this:

enter image description here

Note how I did not even have to "hide" the spinner gif – it reverts back to its original setting when the code behind is done, and that WHOLE FRESH page is now send back down to the client side.

so pop your gif, or toast message, or even a jQuery dialog box up with "please wait". It will all get blown away when the server side code is done, and the new fresh web page comes back down to the client side.

Edit: Ok, assuming you grasp the page life cycle?

So, you can run all the code you want in page load – until the horses come home, but the code and page is STILL up on the server. So you have to LET the page travel down to the client side. And that means your code behind has to FINISH modifying and changing the web page.

THEN and ONLY then does the page travel down to the client side, and display. So, you can CHANGE things in any event on the page but ONLY AFTER the page THEN makes the trip down to the client side will the end user see the results of your code behind changes.

So, what this means in a simple explain?

You have to let the page travel down to the client side. Then click a button to display your message/gif, and then run your server side code.

So, you can do it like this:

first blow out and dump your update panels – you don’t need them.

So, you drop in your div like this, along with a hidden field, and also a button to click that will THEN run your code (but, in place of a user clicking on the button, we will get client side code to click on that button for us!!!).

So, you have this:

        <div id="theprogress" runat="server">
            <h1 style="text-align: center;">MCS File Downloader</h1>
            <asp:Image ID="imgWaitIcon" runat="server" ImageAlign="AbsMiddle" ImageUrl="~/MyPictures/colorchangearrowdown.gif" />
            <h3 runat="server" id="h3Text" style="text-align: center">Processing File...</h3>
        </div>

        <asp:Button ID="cmdLoad" runat="server" Text="Button" ClientIDMode="Static" />

Note the button above, so, put your code in that button:
eg:

 Protected Sub cmdLoad_Click(sender As Object, e As EventArgs) Handles cmdLoad.Click


    Dim Type As String = Request.QueryString("Type")
    If Type = "File" Then
        'TODO
    ElseIf Type = "DB" Then
        OpenDBFile()
    ElseIf Type = "QCBDBYMCSID" Then
        OpenQCBD("BYMCSID")
    ElseIf Type = "QCBDBYNAME" Then
        OpenQCBD("BYNAME")
    Else
        'TODO
    End If

    theprogress.Style.Add("Display", "none") ' hide progress when we are done


End Sub

So, now what will happen?

The page load will inject a button click. Code is done, NOW page travels down to client – the div with your progress + "animation" will display. The JavaScript code you injected in page load will now click that button, and the post back occurs – but the page is displayed, and will remain displayed until such time your code behind is done, and then your code behind hides the animation. Since this suggests some kind of possible file download, then move the hide progress div to the FIRST line of the button click.

Last task: once it all works, then HIDE the button on the page with this:

<asp:Button ID="cmdLoad" runat="server" Text="Button"
    ClientIDMode="Static" style="display:none" />

Answered By – Albert D. Kallal

Answer Checked By – Candace Johnson (BugsFixing Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *