AspAlliance.com LogoASPAlliance: Articles, reviews, and samples for .NET Developers
URL:
http://aspalliance.com/articleViewer.aspx?aId=77&pId=-1
Databinding to Custom Objects
page
by J. Ambrose Little
Feedback
Average Rating: This article has not yet been rated.
Views (Total / Last 10 Days): 25851/ 42

"Hey, Old Woman!"

Published: 30 May 2003

This has got to be one of the coolest things I've done with ASP.NET in quite some time. I'm binding a collection of my own custom business objects to a DataGrid. No data views, no data readers, only the objects that I made, the way I like them. Even Burger King can't beat this!

What's funny is that it's really quite simple, and had I taken the time to figure it out sooner, I could have been eating Whoppers for a long time now. All you need to do is create a collection class that implements IEnumerable, create a private field as an ArrayList, provide accessors to at least add your custom object to the collection, and of course implement the IEnumerable interface by returning the enumerator from your ArrayList's GetEnumerator method. Then you can use the new collection class as the DataSource for your data list controls.

My Custom Object

1:     /// <summary>

2:
/// Contains information about a knight of the round table.
3:
/// </summary>
4: public class KnightOfRoundTable
5: {
6: private string name = string.Empty;
7: private System.Drawing.Color color = System.Drawing.Color.Black;
8: private string quest = string.Empty;
9:
10:
/// <summary>
11:
/// Knight's Name
12:
/// </summary>
13: public string Name
14: {
15: get
16: {
17: return this.name;
18: }
19: set
20: {
21: this.name = value;
22: }
23: }
24:
25:
/// <summary>
26:
/// Knight's Favorite Color
27:
/// </summary>
28: public System.Drawing.Color Color
29: {
30: get
31: {
32: return this.color;
33: }
34: set
35: {
36: this.color = value;
37: }
38: }
39:
40:
/// <summary>
41:
/// Knight's Quest
42:
/// </summary>
43: public string Quest
44: {
45: get
46: {
47: return this.quest;
48: }
49: set
50: {
51: this.quest = value;
52: }
53: }
54: }
55:


As you can see, it's quite a simple object. Just three members, two string and one Color.

 

My Collection Object
 
1:
/// <summary>
2:
/// The knights of the round table.
3:
/// </summary>
4: public class KnightsOfTheRoundTable : System.Collections.IEnumerable
5: {
6:
/// <summary>
7:
/// ArrayList -- handles all the details for the collection.
8:
/// </summary>
9: private System.Collections.ArrayList knights =
new System.Collections.ArrayList();
10:
11: #region IEnumerable Members
12:
/// <summary>
13:
/// Implementation of IEnumerable: Gets an Enumerator.
14:
/// </summary>
15:
/// <returns>An Enumerator of the collection.</returns>
16: public IEnumerator GetEnumerator()
17: {
18: return this.knights.GetEnumerator();
19: }
20: #endregion
21:
22:
/// <summary>
23:
/// Gets or sets a knight by his position at the table.
24:
/// </summary>
25: public KnightOfRoundTable this[int index]
26: {
27: get
28: {
29: if (this.knights.Count > index)
// that position exists
30: return (KnightOfRoundTable)this.knights[index];
31: else
32: throw new ArgumentException(
"That position at the table has not been filled yet!");
33: }
34: set
35: {
36: if (this.knights.Count > index)
// that position exists
37: this.knights[index] = value;
38: else
// it doesn't exist
39: throw new ArgumentException(
"That position at the table has not been filled yet!");
40: }
41: }
42:
43:
/// <summary>
44:
/// Gets or sets a knight by his name.
45:
/// </summary>
46: public KnightOfRoundTable this[string name]
47: {
48: get
49: {
50:
// try to find knight with given name
51: for (int i = 0; i < this.knights.Count; i++)
52: {
53:
// return knight if found
54: if (((KnightOfRoundTable)this.knights[i]).Name.ToUpper()
== name.ToUpper())
55: return (KnightOfRoundTable)this.knights[i];
56: }
57:
// if not found, let them know about it
58: throw new ArgumentException(
"No such knight is honored at our table!");
59: }
60: set
61: {
62:
// try to find knight with given name
63: for (int i = 0; i < this.knights.Count; i++)
64: {
65: if (((KnightOfRoundTable)this.knights[i]).Name.ToUpper()
== name.ToUpper())
66: {
67:
// set found knight to be new knight
68: this.knights[i] = value;
69: return;
70: }
71: }
72:
// if not found, let them know about it
73: throw new ArgumentException(
"No such knight is honored at our table!");
74: }
75: }
76:
77:
/// <summary>
78:
/// Add a knight swearing fealty to Arthur.
79:
/// </summary>
80:
/// <param name="knight">Brave cavalier joining
forces with Arthur.</param>

81: public void Add(KnightOfRoundTable knight)
82: {
83: this.knights.Add(knight);
84: }
85:
86:
/// <summary>
87:
/// Remove a knight who has fallen from grace.
88:
/// </summary>
89:
/// <param name="knight">Knight in disgrace.</param>
90: public void Remove(KnightOfRoundTable knight)
91: {
92: this.knights.Remove(knight);
93: }
94: }
Notice on Line 4 that I'm specifying this class implements the IEnumerable interface--this is key for data binding. You can see on Line 9 that I declare and initialize my private ArrayList. On Lines 16-19, I implement the IEnumerable interface by simply returning the enumerator from my ArrayList. As mentioned, this is the critical part for data binding; the rest of the code is more or less arbitrary, although you will want to at least provide a way to add new objects to the collection as I have in Lines 81-84.

Everything else is pretty much up to you. I chose to add two indexers, one by index (Lines 25-41) and one by name (Lines 46-75). I also provided a Remove method on Lines 90-93. You may notice that in the Add/Remove methods, I'm simply calling the corresponding methods on the ArrayList. In the integer indexer, I guard against an ugly out of bounds exception and instead provide a more thematic exception if the position is not available. In the name indexer, I cycle through the current knights and again throw a thematic exception if the desired object is not found.

 

Usage the First Part: The Page Class

1:     /// <summary>

2:
/// Where the knights meet the old man from Scene 24...
3:
/// </summary>
4: public class TheBridge : System.Web.UI.Page
5: {
6: protected System.Web.UI.WebControls.DataGrid BridgeMaster;
7:
8: private void Page_Load(object sender, System.EventArgs e)
9: {
10: if (!this.IsPostBack)
11: this.BindGrid();
12: }
13:
14: private void BindGrid()
15: {
16: KnightOfRoundTable arthur, galahad, bedevere;
17: KnightsOfTheRoundTable roundTable =
new KnightsOfTheRoundTable();
18: arthur = new KnightOfRoundTable();
19: arthur.Name = "King Arthur";
20: arthur.Color = System.Drawing.Color.Gold;
21: arthur.Quest = "To seek the Holy Grail.";
22: roundTable.Add(arthur);
23:
24: galahad = new KnightOfRoundTable();
25: galahad.Name = "Sir Galahad";
26: galahad.Color = System.Drawing.Color.Yellow;
27: galahad.Quest = "Oooaaaaaah!";
28: roundTable.Add(galahad);
29:
30: bedevere = new KnightOfRoundTable();
31: bedevere.Name = "Sir Bedevere";
32: bedevere.Color = System.Drawing.Color.Blue;
33: bedevere.Quest = "Determine the flight velocity
of an unladen African (or European) swallow.";
34: roundTable.Add(bedevere);
35:
36: this.BridgeMaster.DataSource = roundTable;
37: this.BridgeMaster.DataBind();
38: }
39:
40: #region Web Form Designer generated code
41: override protected void OnInit(EventArgs e)
42: {
43:
//
44:
// CODEGEN: This call is required
by the ASP.NET Web Form Designer.

45:
//
46: InitializeComponent();
47: base.OnInit(e);
48: }
49:
50:
/// <summary>
51:
/// Required method for Designer support - do not modify
52:
/// the contents of this method with the code editor.
53:
/// </summary>
54: private void InitializeComponent()
55: {
56: this.Load += new System.EventHandler(this.Page_Load);
57:
58: }
59: #endregion
60: }

Clearly, the workhorse on this page is the BindGrid method (Lines 14-38). In this, you can see that I create three KnightOfRoundTable objects and name them Arthur, Galahad, and Bedevere respectively, assigning each attributes proper to their characters.  I also create my KnightsOfTheRoundTable collection and add each of these knights to it.  And lastly, on Lines 36-37, I set my KnightsOfTheRoundTable instance to be the DataSource for my BridgeMaster DataGrid and call DataBind on that grid.  And, not entirely insignificantly, I make a call in the Page.Load handler to BindGrid if this is not a post back, on Lines 10-11.

 

Usage The Second Part: Nifty Databinding

1:     <asp:TemplateColumn HeaderText="Favorite Color">

2: <ItemTemplate>
3: <
asp:Label runat="server"
Text='<%# ((BizDataBinding.KnightOfRoundTable)
Container.DataItem).Color.Name
%>'
ID="Label1">

4: </
asp:Label>
5: </ItemTemplate>
6: </
asp:TemplateColumn>
7:

With this section, I just wanted to demonstrate that you can access the members of each instance in the collection in a very real and binding way by casting Container.DataItem as your object type. As you can see, I've done this to access the Color member of my object in order to display its Name property (ignore the line breaks--they're for printability only). If you just use a BoundColumn or DataBinder.Eval, the ToString() method will be called on the particular member. In the case of Color, this is something like "Color [ColorName]" where ColorName is the actual name of the Color.  So if you do not have control over the ToString method on your class members' types, you may need to use this syntax to specify how you want the bound item to render that member.

To sum up, I have demonstrated how to create a collection of custom objects and bind them to a DataGrid.  It's really quite simple once you get down to it--it comes down to just creating a class that implements IEnumerable.  Slick, simple, and cool, what more could you ask for from a development framework?



©Copyright 1998-2024 ASPAlliance.com  |  Page Processed at 2024-04-24 12:02:25 PM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search