)
. Once created, make sure it has the
runat="server" attribute
and a unique
id attribute so that it
can be accessed by the code-behind file. Mine looks something like this:
One thing that the VS.NET IDE does not do for you here is provide the control definition,
like it does for ASP.NET controls. So, we'll have to do this manually.
Go into the codebehind file, and place the following definition to a generic
HTML control where other ASP.NET controls would normally be:
Protected WithEvents pagestats As _
System.Web.UI.HtmlControls.HtmlGenericControl
The next thing we need to do is override the page's Render() method so that we can
do our processing here. If we do it before the render, then we don't have the opportunity to
force status out at-will. Within the Render() method, we can check to what
operation is causing a postback, so we know what operations to do. Our
event handlers that require real-time status, will merely set flags for the
Render() method to react to. Since we all write modular code (right?
:), it should be pretty easy to make calls to our business logic functions from
within Render() instead of our event handlers. Keep in mind that this is
only necessary for those events that require real-time status (which shouldn't
be every one).
OK, so here's what a sample Render() method would look like
that has 2 sections of code that just wait for 10 seconds (which is where a
normally long running operation requiring real-time status would be). Our single button event handler just sets the flag
boolStartEvent for us.
Protected Overrides Sub Render(ByVal writer As
System.Web.UI.HtmlTextWriter)
' Call the parent render and then flush the contents to get them to the browser
quickly
MyBase.Render(writer)
writer.Flush()
Response.Flush()
' Check to see if btnClear was clicked and that's why we're rendering
If boolStartEvent Then
' Send a "starting operation" message
WriteStatusUpdate(writer, "Waiting for 10 seconds ...", False)
' Do your long running operation here - provide status at will
Dim TimerEnd As Long = Now().Ticks + 100000000
While Now().Ticks <= TimerEnd
End While
' Send a "completed operation" message
WriteStatusUpdate(writer, "Done", True)
' Send a "starting operation" message
WriteStatusUpdate(writer, "Waiting for another 10 seconds ...", False)
' Do your long running operation here - provide status at will
TimerEnd = Now().Ticks + 100000000
While Now().Ticks <= TimerEnd
End While
' Send a "completed operation" message
WriteStatusUpdate(writer, "Done", True)
' Clear flag
boolStartEvent = False
End If
End Sub
The first thing our overridden Render needs to do is make a call back to the
MyBase.Render() method so that all of the child controls and other HTML get rendered. Since there's no long-running business logic (anymore), this should be a quick render.
So, what's this function
WriteStatusUpdate? Well, its one of my
common library functions that I use. What it does is use the
Writer object
of the Render() method to push out new HTML to
the
innerHTML attribute of the status object (in this case the
). We push it out in a complete JavaScript tag so that it gets rendered
by the browser immediately, instead of waiting for the ending HTML tag.
Private Sub WriteStatusUpdate(ByVal writer As System.Web.UI.HtmlTextWriter,
_ByVal Status As String, ByVal NewLine As Boolean)
If NewLine Then
writer.Write _
(String.Format("", Status))
Else
writer.Write _
(String.Format("", Status))
End If
writer.Flush()
Response.Flush()
End Sub
Notice that we do both a writer.Flush() and a Response.flush() after
inserting our status message. This is because we
need the writer to flush all the contents of the stream to as a response, but
then we need to flush the response to the client's browser so it'll actually get
rendered real-time.
The text that you send to WriteStatusUpdate can contain embedded HTML (with the exception of
and ), as
long as it is balanced. This means that you can't have an open
tag across multiple calls to the WriteStatusUpdate function.
This is because we're flushing the contents to the browser, so it doesn't
remember anything about the previous HTML statements since it's already rendered
them.
So now, with just a little bit of added code, you can provide real-time status
(when necessary) for your ASP.NET web applications. Enjoy!