Monthly Archives: April 2008

After further testing, I discovered a bug in my GroupedUpdatePanel. It didn’t always function correctly when the postback was initiated by a child control with ChildrenAsTriggers set to true. Any UpdatePanels declared after the initiated panel would update, but those before would not. I’ve corrected this, though it’s now a bit more complicated. There is an processing module which needs to be added to your web.config file in the section. Here’s the link to the corrected file.

Without a doubt, AJAX is one of the most useful web development tools out there. Through AJAX, we finally have a method for developing web pages with robust user interfaces.

The most common and simplest method of AJAX development on ASP.NET is to use the UpdatePanel. While the UpdatePanel creates a lot of overhead, it is very simple to implement. However, sometimes you will have multiple UpdatePanels on a page that relate to each other. In order to reduce your overhead, you will probably want to set thier UpdateMode to Conditional. With the Conditional UpdateMode enabled, they will only update under three conditions (note that nested UpdatePanels are a bit more complicated):

A child control of the UpdatePanel performs a postback, and ChildrenAsTriggers is true

The Update method is explicitly called.

A manually defined trigger is fired.

However, this doesn’t help with firing the other UpdatePanels on the page that are related. While you can update the other panels manually using the Update method or triggers, that can potentially be a lot of work and difficult to maintain.

In order to address this, I’ve created a simple GroupedUpdatePanel. It has a GroupName property which is used to group multiple GroupedUpdatePanels together. If any one UpdatePanel in a group is updated as part of an asynchronous postback, they will all be updated.

There are two important restrictions to note. First, you must set UpdateMode to Conditional. If any one GroupedUpdatePanel in a group is set to Always, they will all update every time. This is a result of the limitations of inheriting from the UpdatePanel class. Second, all of the UpdatePanels must be created and on the page at the time the PreRender event occurs. I’ve seen some reports on the web of certain situations where this is not the case, though I haven’t tested for any of it.

You can download the source for the control here. Feel free to use it in your own applications.

Personally, I find stylesheets to be the best way to apply formating to web pages. Skins certainly have their uses, but they tend to pad out the HTML with lots of redundant information that can be avoided by referencing a stylesheet, thus reducing download times. Stylesheets can be easily added to themes, but sometimes you don’t want to reference all of your stylesheets on every page, which is what happens if you put stylesheets into a theme.

When using master and content pages, this can be a bit tricky. The common solution isn’t all that difficult, you just have to add a content section inside the header of your master page.

Now this works great for most scenarios, but what if you’re using URL rewriting in order to dynamically generate your pages based on the URL that was requested? In that case, the relative path to the stylesheet won’t work. If you know that your web application will always be the root application on the server, you can use a path that starts with /, but that isn’t always the case. What you really need to do is use an application relative path, starting with a ~/.

Normally you can change your link tag to include runat=”server” and it will process application relative paths in the href attribute. However, this doesn’t work on content pages for some reason. Therefore, I’ve created the class below to help.

<Bindable(True), Category(“Behavior”), DefaultValue(“”), Localizable(True)> _ Property href() As String Get Dim s As String = CStr(ViewState(“href”)) If s Is Nothing Then Return String.Empty Else Return s End If End Get

Set(ByVal Value As String) ViewState(“href”) = Value End Set End Property

<Bindable(True), Category(“Behavior”), DefaultValue(“”), Localizable(True)> _ Property rel() As String Get Dim s As String = CStr(ViewState(“rel”)) If s Is Nothing Then Return String.Empty Else Return s End If End Get

Set(ByVal Value As String) ViewState(“rel”) = Value End Set End Property

<Bindable(True), Category(“Behavior”), DefaultValue(“”), Localizable(True)> _ Property type() As String Get Dim s As String = CStr(ViewState(“type”)) If s Is Nothing Then Return String.Empty Else Return s End If End Get

Set(ByVal Value As String) ViewState(“type”) = Value End Set End Property

Public Overrides Sub RenderBeginTag(ByVal writer As System.Web.UI.HtmlTextWriter) If rel &lt;&gt; String.Empty Then writer.AddAttribute(HtmlTextWriterAttribute.Rel, rel) End If If type &lt;&gt; String.Empty Then writer.AddAttribute(HtmlTextWriterAttribute.Type, type) End If If href &lt;&gt; String.Empty Then writer.AddAttribute(HtmlTextWriterAttribute.Href, ResolveClientUrl(href)) End If writer.RenderBeginTag(HtmlTextWriterTag.Link) End Sub