List<T> GridView Target Of Invocation Exception

Posts   
 
    
jmeckley
User
Posts: 403
Joined: 05-Jul-2006
# Posted on: 09-Aug-2007 16:43:34   

adapter 2.0 sql server asp.net 2.0

Summary: I receive a TargetOfInvocation exception if the concrete types are heterogenious

IList<IEquipmentSummaryDTO> results = new List<IEquipmentSummaryDTO>();
GridView.DataSource = results;
GridView.DataBind();

Details: I have an entity hierachy EquipmentStatus +-- PrepareStatus +-- DeployStatus +-- DisposeStatus

my interface which summarizes a status

public interface IEquipmentSummaryDTO
{
    int AssetInstanceId { get; }
    int AssetTag { get; }
    string Description { get; }
    string EquipmentType { get; }
    string Location { get; }
    string Status { get; }
    DateTime? DateToReview { get; }
    IEnumerable<ICustodianDTO> Custodians { get; }
}

Implement interface on supertype

public partial class EquipmentStatusEntity : IEquipmentSummaryDTO
{
    #region IEquipmentSummaryDTO Members

    public int AssetInstanceId { get { return this.Id; } }

    public int AssetTag { get { return this.Equipment.UserDefinedId; } }

    public string Description { get { return this.Equipment.Description; } }

    public string EquipmentType { get { return this.Equipment.EquipmentType.Description; } }

    public virtual string Location { get { return string.Empty; } }

    public virtual string Status { get { return string.Empty; } }

    public virtual DateTime? DateToReview { get { return null; } }

    public virtual IEnumerable<ICustodianDTO> Custodians { get { return new List<ICustodianDTO>().AsReadOnly(); } }

    #endregion
}

Subtypes override virtual properties.

Within my BLL/Managers I have

public interface IEquipmentStatusManager
{
     IEnumerable<IEquipmentStatusDTO> FetchSummaryStatuses(DateTime asOf);
}

Each subtype has a manager which implements this interface.

In my PAL I have the following code to populate my gridview

List<IEquipmentSummaryDTO> results = new List<IEquipmentSummaryDTO>();
foreach (EntityType type in types)
{
    IEquipmentStatusManager manager = EquipmentStatusManagerFactory.Create(type);
    manager.EquipmentTypes = this.view.SelectedEquipmentTypes;
    results.AddRange(manager.FetchAllStatusSummary(this.date));
}

results.Sort(this.sorterToUse);
this.view.Grid.BindTo(results), results.Count;//results and virtual item count

For testing purposes my list returns 3 results (one of each status) On the last line a get a traget of invocation error when binding my 2nd dto in the list.

I found this post [http://www.winterdom.com/weblog/2006/07/27/ITypedListAndPropertyDescriptors.aspx] on creating a TypedBindingList<T>, but that does not resolve my issue either. I implmemented it by changing my last line of code above to

this.view.Grid.BindTo(new TypedBindingList<IEquipmentSummaryDTO>(results), results.Count);

I have read that I need to implement ITypedList (which the post above outlines), but I'm not sure if I'm doing it correctly (using the TypedBindingList<T> object).

2 quick test I did which removed the error, but don't fulfill my requirements: 1. remove the virtual keyword from the interfaced properties on EquipmentStatusEntity 2. return a collection of 1 subtype.

I could: remove the interface from the supertype. create an EquipmentSummaryDTO object which implments the interface add a constructor for each subtype, but that seems to defeat the purpose of the interface.

I also found this post by Frans [http://weblogs.asp.net/fbouma/articles/115837.aspx] I'm not quite sure how to apply this to my scenario.

jmeckley
User
Posts: 403
Joined: 05-Jul-2006
# Posted on: 09-Aug-2007 17:05:02   

ok, so a little more digging and i found a solution, Sean Foy's Defensive DataSource. [http://sean-janus.optionpc.com/me/software/DefensiveDatasource/]

granted I still don't understand the inner workings of why, or how I would fix this manually (my own code). But right now it works.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39910
Joined: 17-Aug-2003
# Posted on: 09-Aug-2007 17:44:03   

I think it occurs because .NET databinding code in general simply does this: 1) if ITypedList is implemented on the bound list, it will ask the ITypedList implemented to provide the property descriptors for the grid. 2) if ITypedList isn't implemented, it will grab the first item, reflect on it and use these property descriptors for the grid.

This thus means: it doesn't change property descriptors per row, it uses 1 set for all the rows. Perhaps you ran into this: databinding with types in a hierarchy is therefore a problem, because if the first item is a supertype it will go OK, but if it's a subtype, it won't, as other instances in the list will be perhaps of a different type and when the grid then wants to read a value through a property descriptor it might be the property isn't there, as it's another type.

Frans Bouma | Lead developer LLBLGen Pro
jmeckley
User
Posts: 403
Joined: 05-Jul-2006
# Posted on: 09-Aug-2007 17:49:55   

that's exactly what happened.

I assume that since I told the datasource it was a List<IEquipmentSummaryDTO> it would know that the properties exist. the contract (interface) says so. but it doesn't work that way, so I'll adapt.

If I hadn't found Sean Foy's datasource helper how would I have Implemented ITypedList and/or Custom Property Attributes to make this work?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39910
Joined: 17-Aug-2003
# Posted on: 10-Aug-2007 16:05:27   

jmeckley wrote:

that's exactly what happened.

I assume that since I told the datasource it was a List<IEquipmentSummaryDTO> it would know that the properties exist. the contract (interface) says so. but it doesn't work that way, so I'll adapt.

If I hadn't found Sean Foy's datasource helper how would I have Implemented ITypedList and/or Custom Property Attributes to make this work?

See my article you linked to, that's about what you've to do (so instead of arraylist, write List<T> and add the elements to that object) simple_smile You can also derive a class from BindingList<T> and override GetItemProperties. Then first call the base version, which should give you the property descriptors of the item, and then decide whether you want to allow all of them, or just a subset. Though that can also be pretty complicated I think.

Frans Bouma | Lead developer LLBLGen Pro