Practical ASP.NET

Databind Page Properties into HTML Tags

Adding some bizarre punctuation marks to the tags in your ASPX file gives you an easy way to move data out of custom properties and into your page.

Please join me in giving a warm welcome back to Peter Vogel for his return to the Visual Studio Magazine fold. Peter has written extensively for VSM in the past, including a monthly column that centered on ASP.NET. Peter will resume writing that column for this, the online version of the magazine. Practical .NET, like its earlier print incarnation, will focus on hands-on information with tips and tricks related to ASP.NET. Feel free to drop Peter a line at peter.vogel(at)phvis.com or use the columns area on this article, whether to say hello, or, even better, to tell him about a topic or question you'd like to see him cover in this space. -Patrick Meader, Editor in Chief, Visual Studio Magazine

By using some databinding syntax in your ASPX file, you can pull the value of any property on your page into any attribute for any tag on your page.

For instance, on one of my client's sites, I wanted to add an HTML tag to cause the page to refresh at regular intervals. I also wanted to set the tag's refresh interval from the user's profile. Databinding the HTML tag was the simplest solution.

The HTML tag that forces a page to refresh goes inside the <head> element at the top of the page and looks like this:

<meta http-equiv="refresh" content="60">

The tag's content attribute controls how often the page should refresh, in seconds (this example has the page refreshing every minute). I looked at a variety of solutions -- including writing to a Literal control -- but I realized that the simplest solution for updating the content attribute was just to databind the attribute to a property in the page, like this:

<meta http-equiv="refresh" 
   content="<%# Me.RefreshInterval %>">

There were two changes I needed to make to the code file to support this change. In the code file for the page, I added a property that returned a value named _RefreshValue:

Protected ReadOnly Property RefreshInterval() As Integer
        Get
            Return _RefreshValue
        End Get
End Property

While I've declared this property as Protected, you can declare the property (I'll call it the "bound property") with any scope you want except for Private.

You also need to call the page's DataBind method to trigger having the data moved to the page. You can put this call in any of the Page's events from PreInit to PreRenderComplete, as long as you've set the value used by the property first. In my case, I added this code to the Page's Load event:

_RefreshValue = Me.Profile.RefreshCycle
Me.DataBind()

Alternatives
While I've used an HTML tag as my example, you can also bind properties on ASP.NET server controls, though it's probably easier to set the equivalent property from code:

<asp:Label ID="IntervalLabel" runat="server" 
   Text="<%#Me.RefreshInterval %>"></asp:Label>

And, if you want, instead of using a Property, you could bind to a function, like this one:

Protected Function RefreshInterval() As Integer
            Return _RefreshValue
End Property

You could even have the function accept a parameter, though you'll have to code the parameter value into your tag. This example passes the word 'Peter' to my RefreshInterval function:

<meta http-equiv="refresh" 
   content="<%# Me.RefreshInterval("Peter") %>">

I'm not clear how this would ever be useful so, for now, it's just a piece of geeky trivia.

No Free Lunch
I believe in many things and one of them is TANSTAAFL: There Ain't No Such Thing as a Free Lunch. Calling the DataBind method on your Page as a whole isn't a free lunch and can be bad for your application.

When a page is first requested, ASP.NET automatically calls the DataBind method on any DataViews on the page. ASP.NET isn't as obliging for controls tied to your bound property, which is why you have to explicitly call the DataBind method yourself.

In my example, I'm calling the DataBind method on the Page as a whole, which, in addition to triggering my bound property, also triggers every DataView on the page to refetch their data. Fortunately, ASP.NET is smart enough not to call the DataBind method twice, so once I issue my DataBind, ASP.NET skips its call and the DataViews only fetch their data once.

You won't be as lucky if the user clicks the Submit button on the page. ASP.NET is smart enough not to call the DataBind method on the DataViews again when a user cycles around on the same page. However, if you call the Page's DataBind method, then you'll not only trigger a refresh of your bound property but a refresh of all the DataViews on the page -- wiping out whatever data your user has entered and refetching your data. It's the data processing perfecta: You're doing too much data access and you've ticked off your users.

There are two solutions. The first is to do what ASP.NET does and only call the page's DataBind method the first time that the page is requested:

If Me.IsPostBack = False Then
            Me.DataBind()
End If

You don't need to keep rebinding because the attributes you've bound will retain their values as the user cycles around on the page, even if the attribute is on an HTML tag.

The second solution is to call the DataBind method on the control itself rather than the page as a whole. For an ASP.NET server-side control, that isn't hard:

Me.IntervalLabel.DataBind()

But to call the DataBind method on an HTML tag, you have to make three changes to the tag before you can access it from code. First, convert the tag into a server-side control by adding the runat attribute, set to server:

<meta runat="server" http-equiv="refresh" 
   content="<%# Me.RefreshInterval %>">

Then give the tag an id attribute whose value you can use to reference the tag from code. In this example, I've given the id attribute the value MetaTag:

<meta runat="server" id="MetaTag" http-equiv="refresh" 
   content="<%# Me.RefreshInterval %>">

Finally, make the tag wellformed by closing it properly. You can do that either by adding a slash to the end of the tag, or -- as I've done here -- by adding a closing tag:

<meta runat="server" id="MetaTag" http-equiv="refresh" 
   content="<%# Me.RefreshInterval %>"></meta>

You can now call the control's DataBind() method as you would for any server-side control:

Me.MetaTag.DataBind()

Personally, I prefer the second solution: calling a DataBind method targeted just for the control that's to be updated. It's Vogel's Fifth Law: Never do any more work than you have to.

About the Author

Peter Vogel is a system architect and principal in PH&V Information Services. PH&V provides full-stack consulting from UX design through object modeling to database design. Peter tweets about his VSM columns with the hashtag #vogelarticles. His blog posts on user experience design can be found at http://blog.learningtree.com/tag/ui/.

comments powered by Disqus
Upcoming Events

.NET Insight

Sign up for our newsletter.

I agree to this site's Privacy Policy.