views:

1258

answers:

6

I have bound an ASP.net GridView to a collection of anonymous types.

How can I reference one of the properties of the anonymous types in the RowDataBound event handler?

I am already aware of the way to cast the anonymous type like this:

protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        var AnonObj = Cast(e.Row.DataItem, 
          new { StringProperty = "", BoolProperty = false, IntProperty = 0 });

        if (AnonObj.BoolProperty)
        {
            e.Row.Style.Add(HtmlTextWriterStyle.Color, "Red");
        }
    }
}


T Cast<T>(object obj, T type)
{
    return (T)obj;
}

I think most would say this is messy, even though it does work. In my real code, I have more than 3 properties and I would have to update code in two places anytime I added or reordered the properties of my anonymous type.

Is there a better way to tell e.Row.DataItem that it has a specific property of a specific type and force the object to give me that value (besides creating a class)?

+5  A: 

A better way would be to create a type to handle this so you don't have to do all that casting to use the anonymous type.

Andrew Hare
+5  A: 

Look into using reflection.

Example:

object o = e.Row.DataItem;
Type t = o.GetType();
PropertyInfo pi = t.GetProperty("StringProperty");
if (pi != null && pi.PropertyType == typeof(string))
{
  // the property exists!
  string s = pi.GetValue(o, null) as string;
  // we have the value
  // insert your code here
  // PROFIT!  :)
}

Error-checking and optimization left as an exercise to the reader.

leppie
Please give specific examples on how to this. I tagged this question with reflection, because I had the feeling I could use reflection. But, I don't know exactly what to do. Thanks.
Ronnie Overby
Thanks for the example. I am going to try it out, even though I will probably just create a class for this.
Ronnie Overby
+1  A: 

No, I don't believe there's any better way than this. The C# guys don't really support using anonymous types outside of local method scope (i.e. here you have an anonymous type attached to your Row object.)

The usual suggestion would be to make a real class instead.

mquander
+3  A: 

The way you are using (cast by example) is messy and very brittle - I really don't recommend it (if you add a property, or name them in a different order, it'll break; etc). The better approach is to use your own named type in the projection.

Marc Gravell
How do you mean 'name them in a different order'? Does that mean an anonymous type is layout sensitive (like a struct)?
leppie
IDK if a struct is or not, but yes. If I add, remove, rename, or reorder any of those properties, the cast WILL NOT WORK.
Ronnie Overby
Wow, I just checked for myself! I wonder how I missed that? :)
leppie
The spec dictates that anon-types are unique by name **and** order - so new {Foo=123, Bar="abc"} is completely different to new {Bar="abc", Foo=123}. IIRC, partly to do with the generics and GetHashCode() etc- but just worth knowing ;-p (i.e. don't worry about the details unless you have to...)
Marc Gravell
A: 

The method you're using to cast the anonymous object (while very cool) is a hack. It works simply because the C# compiler is smart enough to only create one instance of the Anonymous Class for the entire app if the Properties are the same. So there really is no benefit in using anonymous types, since a class is being created behind the scenes anyway. Yes, you can hack it, you can use reflection, but seriosuly, why bother? What benefit is there to using Anonymous types in this case?

BFree
"C# compiler is smart enough" - well, the spec guarantees this behavior, but I agree it is brittle and not a good idea.
Marc Gravell
Well it does guarantee it, you're right, but even the slightest difference, like say you reorder the Properties, and it'll already create a new Type for you. So it's smart, but not THAT smart :)
BFree
I agree entirely with your point - I'm merely pointing out that it is the spec, not the compiler, that does this. Sometimes this is important, as it means it isn't simply working because of an implementation detail.
Marc Gravell
"why bother? What benefit is there to using Anonymous types in this case?" - I wont bother if I don't find out that there is an incredibly easy and convenient way to do what I want to do. That's why I am asking. I am pretty sure I will end up creating a class for this.
Ronnie Overby
Well, the "cleanest" way IMO would be to take what leppie wrote and add that as an extension method on object something like object.GetProperty(string name). That way you can just call this method on your anonymous type object, and get your value. That's the cleanest IMO without creating a class.
BFree
A: 

What I do is ... for example,

string Name = (string)DataBinder.Eval(dataItem.DataItem, "Name");

.. but this is in a listview ItemDataBound event handler. Thought it might be useful for someone?

Stuart