posted on Wednesday, February 02, 2005 9:41 AM
by
mlorengo
Handling Complex Objects in the GridView Control
The new GridView in Asp.Net 2.0 makes displaying business objects just as
easy as displaying DataSets. However when it comes to displaying complex
business objects (my definition) it isn't that apparent (at least to me) how to
go about doing this.
When I say complex business object, I mean a business object that is composed
of more than just properties of simple types (int, string, etc), but instead has
properties consisting of other objects or even collections of objects. A prime
example of this in my case is the Wine class.

In the class diagram above, you can see that the Wine has a Varietals
property that is a collection of WineVarietal classes, in turn, the WineVarietal
class is composed of an Id, Percent, and a Varietal class. We're talking
complex, not rocket science, but complex. The Class diagram illustrates how I
chose to model the relationship of a Wine to it's Varietal. In this case a Wine
can be composed of one or more varietals of grape in varying percentages. Please
see my
Varietal is the Spice of Life for more details on the modeling.
In the declaration of the .aspx page GridView control, I have the following
fields bound. Notice the Varietals field, it's the same as all of the others.
<asp:gridview id="wineGridView" runat="server" AutoGenerateColumns="False">
<Columns>
<asp:BoundField HeaderText="Id" DataField="Id" SortExpression="Id"></asp:BoundField>
<asp:BoundField HeaderText="Vintage" DataField="Vintage" SortExpression="Vintage"></asp:BoundField>
<asp:BoundField HeaderText="Name" DataField="Name" SortExpression="Name"></asp:BoundField>
<asp:BoundField HeaderText="Appellation" DataField="Appellation" SortExpression="Appellation"></asp:BoundField>
<asp:BoundField HeaderText="Varietals" DataField="Varietals" SortExpression="Varietals"></asp:BoundField>
</Columns>
</asp:gridview> |
However the GridView will display the following. See how the Varietals column
simply outputs the class name of the field. What I would really like to do is
have it display the list of varietal components, along with there percentage
makeup.
| Id | Vintage | Name | Appellation | Varietals |
| 82 | 2000 | 2000 Ravenswood Winery Pickberry Vineyards Sonoma Mountain | Sonoma Mountain | Lorengo.VirtualCellar.Business.WineVarietalCollection |
It turns out that the GridView supports the concept of a <asp:TemplateField>
which allows for the customization of the output. What I will need to do is
replace the <asp:BoundField> for the Varietals property, and instead insert a <asp:TemplateField>.
Inside of the <asp:TemplateField> I will add a DataList control, and give it an
id="varietalDataList". For the <ItemTemplate> in the DataList I will use the
Container.DataItem property, which should point to a WineVarietal item in my
Varietals collection. I can then cast the DataItem to the appropriate type.
For example ((WineVarietal)Container.DataItem).Percent will give me the
percentage of the grape varieatal in the current wine. See the code below.
<asp:gridview id="wineGridView" runat="server" AutoGenerateColumns="False" OnRowDataBound="WineGridView_RowDataBound">
<Columns>
<asp:BoundField HeaderText="Id" DataField="Id" SortExpression="Id"></asp:BoundField>
<asp:BoundField HeaderText="Vintage" DataField="Vintage" SortExpression="Vintage"></asp:BoundField>
<asp:BoundField HeaderText="Name" DataField="Name" SortExpression="Name"></asp:BoundField>
<asp:TemplateField HeaderText="Varietals" SortExpression="Varietals" >
<ItemTemplate>
<asp:DataList id="varietalDataList" runat="server">
<ItemTemplate>
<%# ((Varietal)((WineVarietal)Container.DataItem).Varietal).Name %>
(<%# ((WineVarietal)Container.DataItem).Percent %>%)
</ItemTemplate>
</asp:DataList>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="Appellation" SortExpression="Appellation"></asp:BoundField>
<asp:BoundField HeaderText="ItemState" DataField="ItemState" SortExpression="ItemState"></asp:BoundField>
</Columns>
</asp:gridview>
|
Ahh, but how does it know to bind the items in the DataList to the
WineVarietal object of the current wine? You may have noticed the added
attribute in the <asp:GridView> control. To be more specific,
OnRowDataBound="WineGridView_RowDataBound".
This let's us add some special code to handle the wiring up of the Wine's
Varietals collection in the pages codebehind.
protected void WineGridView_RowDataBound(object sender, GridViewRowEventArgs e)
{
Wine w = null;
GridViewRow r = e.Row;
if (r.DataItem != null) // Make sure we're not in the Header or Footer row
{
w = r.DataItem as Wine;
}
DataList varietalDataList = e.Row.FindControl("varietalDataList") as DataList;
if (varietalDataList != null && w != null)
{
varietalDataList.DataSource = w.Varietals;
varietalDataList.DataBind();
}
|
For each row in the GridView (including the Header and Footer rows), we will
find "varietalDataList" control and update it's DataSource to the Varietals
collection of the current Wine object. Then we call it's DataBind() method and
woo hoo! Here's what we get!
| Id | Vintage | Name | Varietals | | ItemState |
| 82 | 2000 | 2000 Ravenswood Winery Pickberry Vineyards Sonoma Mountain |
| Merlot (53%) |
| Cabernet Sauvignon (45%) |
| Cabernet Franc (2%) |
| Sonoma Mountain | Clean |
I like it. Now, I'm not sure if this is the best way to do it. It just works
for me. If anyone has any other suggestions as to accomplish this, I would sure
be interested in hearing about it. My next step is to code up a general Producer
and Wine search page, so I'll take what I've learned today and apply it to those
pages.