Home > .net 3.5, AJAX, c#, Microsoft, Visual Studio 2008 > Wrapping Up CrossBrowserUpdateProgress Into a Control

Wrapping Up CrossBrowserUpdateProgress Into a Control

August 11, 2008

Download the Source.

A few weeks ago, I wrote about the joys of trying to create a cross browser UpdateProgress panel (or more to the point, work around oddities with IE6 CSS).

The post was fine, and the method works quite well; however, it’s not easily reproducable in it’s current form.  A custom web control; however, would solve that in a snap.

In this custom control, I’ll:

  • Determine if it’s IE6 or not and apply the approprate CSS
  • Accomodate the glitch where DropDownLists shine through in IE6
  • Provide public properties for the AssociatedUpdatePanelId and the text to appear in the UpdateProgress

Later on, I’ll probably tweak this to simply make the ProgressTemplate a public property—just like a standard UpdatePanel; however, for now, this meets the needs—a basic update progress control.  Simple is good.🙂

Basic CBUP

On the ASPX side, the code usage is quite simple:

<ts:CrossBrowserUpdateProgress runat=”server” ID=”cbup”

AssociatedUpdatePanelID=”UpdatePanel1″
DialogText=”Please wait…” />

Behind the scenes, the code is pretty spartan.  The WebControl renders an UpdateProgress control, applies the DialogText and AssociatedUpdatePanelID properties, creates the ProgressTemplate with the IFrame (to fix IE6 drop down lists), modal background, and the dialog itself.  Let’s take a look at the code.

There are three methods that are overridden: OnPreRender (to set the CSS), RenderContents (to create the controls and set a final ZIndex for IE6), and the actual CreateChildControls.

OnPreRender

Thankfully, the Request object has a helpful HtmlBrowserSpecifications array that keeps track of properties such as the browser, versions, javascript compatibility, etc.  From this, we can determine our IE 6 users and provide the approprate CSS.

protected override void OnPreRender(System.EventArgs e)

{

if (this.Context.Request.Browser.Version == “6.0” &&

this.Context.Request.Browser.Browser == “IE”)

{

       var ie6Css =

Page.ClientScript.GetWebResourceUrl(GetType(), “ie6.css”);

var iis6CssLink = new HtmlLink { Href = ie6Css };

       iis6CssLink.Attributes.Add(“rel”, “stylesheet”);

       iis6CssLink.Attributes.Add(“type”, “text/css”);

       this.Page.Header.Controls.Add(iis6CssLink);

}

 

var generalCss =

Page.ClientScript.GetWebResourceUrl(GetType(), “general.css”);

var generalCssLink = new HtmlLink { Href = generalCss };

       generalCssLink.Attributes.Add(“rel”, “stylesheet”);

       generalCssLink.Attributes.Add(“type”, “text/css”);

       this.Page.Header.Controls.Add(generalCssLink);

 

       base.OnPreRender(e);

}

The CSS files are included as embedded resources (and should be approprately marked in the AssemblyInfo.cs) with the control.

RenderContents

RenderContents is nice and simple—set the ZIndex of the entire control, make sure that everything is in place, and render!

protected override void RenderContents(HtmlTextWriter output)

{

output.AddStyleAttribute(HtmlTextWriterStyle.ZIndex, “99999999”);

       EnsureChildControls();

       base.RenderContents(output);

}

Is the ZIndex necessary?  Quite frankly, I’m not sure.  For IE6, 3/5ish tests failed WITHOUT it—the drop down lists still shined through in spite of the IFrame.  Having it in there seemed to guarantee it working.  Your mileage may vary.🙂

CreateChildControls

The CreateChildControls method is responsible for generating the actual UpdateProgress control and adding it to the WebControl for rendering.

protected override void CreateChildControls()

{

base.Controls.Clear();

 

       if (!ChildControlsCreated)

       {

              var baseProgress = new UpdateProgress

             {

                     DisplayAfter = 100,

DynamicLayout = false,

AssociatedUpdatePanelID = AssociatedUpdatePanelID,

ProgressTemplate = new ProgressTemplate()

};

this.Controls.Add(baseProgress);

 

}

base.CreateChildControls();

}

Seems a bit to easy, huh?  It is.  Notice that the ProgressTemplate is creating a new ProgressTemplate?  ProgressTemplate is a Template (or ITemplate) and to dynamically assign it, I had the best luck creating an internal class to handle rendering the template—this is where the guts of the control actually fall.

ProgressTemplate

The only required method of an ITemplate is InstanciateIn(Control) and I’m more than happy to accomdate.

/// <summary>

/// Fake ProgressTemplate for the UpdatePanel.ProgressTemplate.

/// </summary>

internal class ProgressTemplate : ITemplate

{

public void InstantiateIn(Control container)

       {

// Create IFrame for IE6 “coverups” of drop down lists.

       if (HttpContext.Current.Request.Browser.Version == “6.0” &&

HttpContext.Current.Request.Browser.Browser == “IE”)

{

var iFrame =

new LiteralControl(@

<iframe id=’UpdateProgressHideSelect’>

</iframe>”);

container.Controls.Add(iFrame);

 

       }

       var progressBackground =

new LiteralControl(@

<div id=’UpdateProgressModalBackground’>

</div>”);

 

var progressDialog =

new LiteralControl(@

<div id=’UpdateProgressPanel’>

<div id=’UpdateProgressText’>” +

_dialogText +

“</div></div>”);

 

                container.Controls.Add(progressBackground);

                container.Controls.Add(progressDialog);

}

}

To access the _dialogText inside the internal ProgressTemplate class, you can either pass it as a variable when you create ProgressTemplate OR set your private field to static.

Put that all together and the output HTML is nice and tidy:

<span id=“cbup”>

<div id=“ctl03”

style=“z-index: 99999999; visibility: hidden; display: block;”>

<div id=“UpdateProgressModalBackground”/>

<div id=“UpdateProgressPanel”>

<div id=“UpdateProgressText”>Please wait…</div>

</div></div>

</span>

There’s still work to do, but it provides a nice base to toss in my controls library.

%d bloggers like this: