Wednesday, April 8, 2009

Declaratively Binding ASP.NET Server Control Properties

Today I had the need to bind the 'Visible' property of an ASP.NET PlaceHolder control to a boolean property defined in my code-behind. This was certainly not the first time I've had to do this but it seems like every time I need to do it I have a hard time remembering the correct way to do it. So now that I've figured it out (again) I'm going to make a short post here about how to do it, both for my reference and yours. With client-side controls you can use the <%= %> operators to bind properties to code-behind generated values. For instance, let's say that for some reason I wanted to define the URL to my home page in my code-behind. I could put a property for accessing this value in the code-behind like so:
protected string HomePageUrl
{
 get
 {
  return "http://mysite.com/default.aspx";
 }
}

Then in my .aspx file I could create my client-side href tag declaratively like so:
<a href='<%= HomePageUrl %>'>Home</a>
That works just fine. But with server-side controls the above method will simply not work. In my case I wanted to bind the Visible property of the PlaceHolder control to a boolean property in my code-behind. Let's assume a simple property that always returns true:
protected bool ShouldBeVisible
{
 get
 {
  return true;
 }
}

And then we try to use the same technique we used with the anchor tag with the PlaceHolder:
<asp:PlaceHolder ID="PH1" runat="server" 
Visible="<%= ShouldBeVisible %>" />


This builds OK but when we try to load the page we get a Parser Error: "Cannot create an object of type 'System.Boolean' from its string representation '<% ShouldBeVisible %>' for the 'Visible' property." This is causing a problem for two reasons as far as I understand it. Firstly the <%= %> operator returns a string, not a boolean. Secondly the <%= %> operator doesn't get executed until the page is being rendered. This is way too late in the page lifecycle for the property to properly evaluated and applied. Luckily there is a simple way to solve the problem and that is to use the binding operator instead: <%# %>. This operator gets processed during calls to the DataBind method of whatever it's parent is. In my case I was doing this inside a ListView and the call to the ListView's DataBind method was enough to cause the operator to be evaluated. You can however do this anywhere on your page. Just remember that to get the operator to actually be processed you'll need to call Page.DataBind() somewhere. The Page_Load event handler is usually going to be the best place for this probably. So the proper code to bind the Visible property of my PlaceHolder to a value from the code-behind is:
<asp:PlaceHolder ID="PH1" runat="server" 
Visible="<%# ShouldBeVisible %>" />


Hope this helps you out!

4 comments:

Sreeranab said...

Is it possible to set like this via a object

Example

i am defining a class with properties . now i am creating instance of a object say Employee

is it possible to say like <%#employee.property%>

Sreeranab said...

I created a static class and specified <% #staticclassname.property%> and invoked databind method of the respective controls.

John Ward said...

Thank you! The Page.DataBind() detail is missing from every post I've read on this topic, and is the key to getting me moving again. Thx.

Andrew said...

This has the unfortunate side effect of running DataBind() on all child controls, which is often undesired...