Late Binding of C# objects from NHibernate into the ASP.NET DataGrid control
Posted by Dave Hrycyszyn 26th April 2006 in Head LabsIt's not a full example with code downloads, but here's an example of late binding in C#, when we don't know whether a class being bound into a DataGrid is going to be of type Article, Vacancy, Image, or whatever. I've found this to be a good approach when customizing a DataGrid that we can re-use in our internally-developed content management system.
Since the objects we get back from NHibernate, wonderfully enough, are just objects of the type we ask for instead of some stupid intermediate typeless object contained in a DataSet, we can just bind them into the DataGrid. The one thing that's necessary is that we need to know anything going into the DataGrid needs to implement certain properties, like Title and Active.
First, we define an interface that content objects must implement:
-
using System;
-
using System.Collections;
-
-
namespace com.headlondon.cms.models
-
{
-
/// <summary>
-
/// IContent interface specifies the methods and properties that a piece of content must
-
/// implement. Other classes, such as headcms.admin.common.controls.datagrid.HeadGrid
-
/// rely on these details to be able to do late binding.
-
/// </summary>
-
interface IContent
-
{
-
int Id { get; set; }
-
string Title { get; set; }
-
bool Active { get; set; }
-
void Save();
-
void Delete();
-
}
-
}
-
Then we make sure our concrete classes do in fact implement this interface:
-
using System;
-
using System.Collections;
-
using com.headlondon.cms.dataaccess;
-
-
namespace com.headlondon.cms.models
-
{
-
/// <summary>
-
/// The base Article class representing HTML text content in the system. It can show up as-is, but is
-
/// also used by other classes such as Vacancy and FAQ for inheritance.
-
/// </summary>
-
public class Article : IContent
-
{
-
private ArticleDao dao = new ArticleDao();
-
-
private int id;
-
private string title;
-
private string body;
-
private bool active;
-
-
/// <summary>
-
/// Constructor.
-
/// </summary>
-
public Article()
-
{
-
Id = -1;
-
Active = false;
-
}
-
-
/// <summary>
-
/// Save the article to the database.
-
/// </summary>
-
public void Save()
-
{
-
dao.Save(this);
-
}
-
-
public static IList List()
-
{
-
ArticleDao dao = new ArticleDao();
-
return dao.List(typeof(Article));
-
}
-
/// <summary>
-
/// List articles that share a property value.
-
/// </summary>
-
public static IList List(string property, object propertyValue)
-
{
-
ArticleDao dao = new ArticleDao();
-
return dao.ListByPropertyValue(typeof(Article), property, propertyValue);
-
}
-
-
/// <summary>
-
/// List articles that share a property, order by an orderPropertyName and a value "ASC" or "DESC".
-
/// </summary>
-
public static IList List(string property, object propertyValue, string orderPropertyName, string orderValue)
-
{
-
ArticleDao dao = new ArticleDao();
-
return dao.ListByPropertyValueOrderBy(typeof(Article), property, propertyValue, orderPropertyName, orderValue);
-
}
-
-
/// <summary>
-
/// List articles by an orderPropertyName, and a value "ASC" or "DESC".
-
/// </summary>
-
public static IList List(string orderPropertyName, string orderValue)
-
{
-
ArticleDao dao = new ArticleDao();
-
return dao.List(typeof(Article), orderPropertyName, orderValue);
-
}
-
-
/// <summary>
-
/// Get an article by its Id.
-
/// </summary>
-
public static Article Get(int id)
-
{
-
ArticleDao dao = new ArticleDao();
-
return dao.Get(typeof(Article), id) as Article;
-
}
-
-
/// <summary>
-
/// Delete the article object from the database.
-
/// </summary>
-
public void Delete()
-
{
-
dao.Delete(this);
-
}
-
-
// Accessors
-
-
-
/// <summary>
-
/// The Article's Id.
-
/// </summary>
-
public int Id
-
{
-
get { return id; }
-
set { id = value; }
-
}
-
-
/// <summary>
-
/// The Article's Title.
-
/// </summary>
-
public string Title
-
{
-
get { return title; }
-
set { title = value; }
-
}
-
-
/// <summary>
-
/// The Article's Body text.
-
/// </summary>
-
public string Body
-
{
-
get { return body; }
-
set { body = value; }
-
}
-
-
/// <summary>
-
/// Is this Article active? I.e. does it show up on the public site?
-
/// </summary>
-
public bool Active
-
{
-
get { return active; }
-
set { active = value; }
-
}
-
}
-
}
Then when we want to grab a piece of content from the database and stick it in a DataGrid using a DataBind method call, we don't have to worry about what its concrete class is, we just say something like this:
-
-
/// <summary>
-
/// Handler for the DataBinding event where we bind the data for a specific row
-
/// to the CheckBox.
-
///
-
/// Any type in the DataGrid must implement the interface IContent, which specifies that the
-
/// item must have an Id, Active, and a bunch of other properties.
-
/// </summary>
-
private void BindData(object sender, EventArgs e)
-
{
-
CheckBox checkBox = (CheckBox)sender;
-
DataGridItem container = (DataGridItem) checkBox.NamingContainer;
-
IContent content = (IContent)container.DataItem;
-
checkBox.Checked = content.Active;
-
HtmlInputHidden oHid = (HtmlInputHidden)container.FindControl("oHid");
-
oHid.Value = content.Id.ToString();
-
}
-
That code was from a custom CheckBoxItem class, the custom DataGrid class does something like this during its DataBind event:
-
-
IContent content = (IContent) e.Item.DataItem;
-
((HyperLink)e.Item.Cells[0].FindControl("lblC1")).Text = content.Title;
-
((HyperLink)e.Item.Cells[0].FindControl("lblC1")).NavigateUrl = formPath + content.Id;
-
This blog post is just to put you on the right track, if you need more help with this sort of thing just reply in the comments. It's been a pleasant way to get a lot of functionality out of very little code.
Web References:
If you're not familiar with the basic concepts, there is a good discussion of late binding in C# and VB.NET here. Oddly it doesn't include this interface trick above, so maybe this will help someone.
Search
Categories
- Thoughts
(19)
- News
(30)
- Head Labs
(13)
- Project launch
(10)
- Life at Head
(10)
Monthly Archives
- January 2009 (1)
- December 2008 (3)
- November 2008 (4)
- September 2008 (1)
- August 2008 (1)
- July 2008 (1)
- June 2008 (1)
- May 2008 (2)
- March 2008 (1)
- February 2008 (1)
- January 2008 (1)
- November 2007 (2)
- August 2007 (1)
- May 2007 (2)
- April 2007 (5)
- March 2007 (11)
- February 2007 (10)
- January 2007 (4)
- November 2006 (2)
- September 2006 (4)
- August 2006 (1)
- July 2006 (1)
- June 2006 (3)
- May 2006 (1)
- April 2006 (3)
- March 2006 (7)
- February 2006 (5)
- January 2006 (1)
- November 2005 (1)
Just as a note: thinking about it some more, I really prefer this way of doing late binding to the loose-typing VB.NET way. The reason is pretty simple - there is absolutely no way to screw it up, due to type safety. In VB.NET, you could just say something like:
Option Strict Off
…and then proceed to access any property or method of the Article object (which is in fact just an object). The trouble would be that if you blew it and forgot to implement, let’s say, Title in one of your classes, you’d get a runtime error when a user tried to access your code. Using the IContent interface ensures that any class that implements IContent *must* have a Title, Id, etc. So, even in VB.NET, this technique of casting to an interface is still the way to go.