Custom Data Binding for Server Controls
page 5 of 7
by Justin Lovell
Feedback
Average Rating: This article has not yet been rated.
Views (Total / Last 10 Days): 34827/ 81

Binding Logic for the TitleDescription control

Now I am going to develop the data binding logic of the TitleDescription control. It will be explained after the listing:


private string pDataTitleField;
private string pDataDescriptionField;


// indicates which column the title value resides in
public string DataTitleField {
   get { return pDataTitleField; }
   set {
      if ((value == null) && (value.Length == 0))
         throw new ArgumentNullException();
      else
         pDataTitleField = value;
   }
}


// indicates which column the description value resides in
public string DataDescriptionField {
   get { return pDataDescriptionField; }
   set {
      if ((value == null) && (value.Length == 0))
         throw new ArgumentNullException();
      else
         pDataDescriptionField = value;
   }
}


public object DataSource {
   get { return ViewState["DataSource"]; }
   set {
      if (value is DataTable) {
         // finally accepts a data table – through conversion or straight 
         // from the page developer. However, we take precaution to that it is trimmed
         DataTable externalTable = (DataTable)value;
         DataTable internalTable = new DataTable();
         Hashtable columns = FindDataColumns();
 
         foreach (string key in columns.Keys)
            internalTable.Columns.Add(new DataColumn(key));
 
         foreach (DataRow eRow in externalTable.Rows) {
            DataRow iRow = internalTable.NewRow();
            internalTable.Rows.Add(iRow);
 
            foreach (DataColumn iColumn in internalTable.Columns)
               iRow[iColumn] = eRow[(string)columns[iColumn.ColumnName]];
         }
 
         ViewState["DataSource"] = internalTable;
      }
      else if (value is DataSet) {
         // deals with data sets and selects the first data table
         if (((DataSet)value).Tables.Count == 0)
            throw new Exception("The dataset does not have any tables.");
         else
            DataSource = ((DataSet)value).Tables[0];
      }
      else {
         // we are now dealing with more advanced objects.
         // Additional things need to be setup to ensure best performance.
         DataTable table = new DataTable();
         Hashtable columns = FindDataColumns();
 
         table.Columns.Add(new DataColumn("Title"));
         table.Columns.Add(new DataColumn("Description"));
 
         if (value is IDataReader) {
            // this deals with all the data readers
            int nextColumn = 0;
            IDataReader reader = (IDataReader)value; 
 
            while (reader.Read()) {
               DataRow row = table.NewRow();
               table.Rows.Add(row);
 
               foreach (string key in columns.Keys) {
                  if (columns[key] == null) {
                     row[key] = reader[nextColumn]; 
                     nextColumn++;
                  }
                  else
                     row[key] = reader[columns[key].ToString()]; 
               }
            } 
         }
         else if (value is IEnumerable) {
            // this deals with the data views, custom collections and XML nodes.
            // The problem is that this may be more time consuming
            foreach (object obj in (IEnumerable)value) {
               DataRow row = table.NewRow();
               table.Rows.Add(row);
 
               foreach (string key in columns.Keys)
                  row[key] = DataBinder.Eval(obj, columns[key].ToString()); 
            }
         }
         else
            // we cannot accept the data source – we do not recognize it
            throw new Exception("Invalid Data Source type.");
 
         DataSource = table;
      }
   }
}


private Hashtable FindDataColumns() {
   Hashtable columns = new Hashtable();
 
   // use the default column if none selected
   columns.Add("Title", DataTitleField);
   columns.Add("Description", DataDescriptionField);
 
   return columns;
}

 

Right – there are plentiful of comments in the above figure. I do not think that anyone will have a problem with it… but I have the feeling that I should add a simple summary. Essentially, what happens is that the data source is recycled on the fly until it reaches a DataTable state. It sort of bubbles a conversion – the above can even bind to XML – XMLNodes to be exact for now. But the DataTable class does not have to be the end objective of every data binding scenario: it can be XML itself – it all depends on you as the developer.

 

With the above code sample, it is picky on the columns that it does save – the reason is to down size view state. We could be given a data reader with ten columns and we only need two of them… why save the rest when we are not going to use it? The data in the view state can get tremendously big because we are saving data that we do not need in the first place.

 

However, if you do have a template based control – there is no telling what data is required. To combat this, you will unfortunately have to save the entire DataTable to the view state – and that is the very reason why controls like the DataGrid control and the Repeater control can have a huge footprint on the view state.

 

There is one thing missing from the TitleDescription control – and that is the DataBind method. If you have a quick breeze through the documentation, you would have noticed that there is a DataBind method on the Control class. The DataBind method is marked virtual so we can easily override it:

 

public override void DataBind() {
   if (DataSource != null) {
      foreach (DataRow row in ((DataTable)DataSource).Rows) {
         TitleDescriptionItem item = new TitleDescriptionItem();
 
         Items.Add(item);
         item.DataItem = row;
         item.DataBind();
      }
   }
   else
      throw new Exception("DataSource is null.");
}

 

That code seems simple enough – assign a sub-data source to the new TitleDescription control and bind it. Simple as that and the binding logic of that control falls onto the next page.


View Entire Article

User Comments

Title: Great Article!   
Name: NiQuil
Date: 2010-01-18 9:53:29 AM
Comment:
This helped me a lot! I am totally new to programming and this has been a great tutorial for me.
I am creating my own control library with databound controls, with XHTML output and taking into account the 125 (very) strict rules for the Dutch Government Guidelines for the web.

I noticed this is a Visual studio 2003 (?) project since I had to convert it to my 2008.

Isthis still "the way to go" on this subject, or have new developments, maybe on Microsoft's part, on this subject seen the light of day?

Kind regards,

NiQuil
Title: Why Doesn't It Work   
Name: Marc
Date: 2009-06-04 3:09:50 PM
Comment:
My TitleDescriptionItems never display. CreateChildControlsnever gets hit. Why?
Title: DataSourceID   
Name: Andrew
Date: 2008-06-20 11:11:26 AM
Comment:
Great article, however I was wondering how would one implement the DataSourceID and DataMember properties?

Product Spotlight
Product Spotlight 





Community Advice: ASP | SQL | XML | Regular Expressions | Windows


©Copyright 1998-2024 ASPAlliance.com  |  Page Processed at 2024-10-16 12:28:16 AM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search