CodeSmith Community
Your Code. Your Way. Faster!

Problem with ITypedList.GetItemProperties and child collections.

Latest post 09-06-2006 5:31 AM by Duncan Stewart. 3 replies.
  • 08-02-2006 12:38 AM

    • jasona941
    • Not Ranked
    • Joined on 08-02-2006
    • Posts 4
    • Points 110

    Problem with ITypedList.GetItemProperties and child collections.

    I'm running VS2005 and have tried both the beta and CTP nightly build (20060801).

    I'm trying to bind an object of type TList<A> to an Infragistics UltraGrid control. I haven't tried using the stock grid control to see if it behaves the same way but plan to as soon as I understand some of the other problems I'm having with adding and deleting.

    Here's the issue at hand. Object of type "A" has a BCollection property of type TList<B>. What I want to try to accomplish is to get the grid to render this hierarchy using object data binding. The "A" properties for each item in TList<A> display ok, but when I expand a row to try and view TList<B> the control throws an exception.

    After a bit of digging, I found that the ListBase class' implementation of GetItemProperties tries to return properties of  TList<B>. This didn't sound right to me since what I really want to show in the grid was B's properties, not TList<B>. I found Frans Bouma's implementation of ITypedList and used his TypeContainedAttribute class to get to B's property descriptors.

    Has anyone else run into this? Is this really a bug or would this fix break the way other stock controls perform complex data binding?

    Here's the what I did to get it working.

    Add the TypeContainedAttribute class definition to EntityHelper.cs:

    /// <summary>
    /// Attribute to use on properties which return a weakly typed collection.
    /// This attribute will tell the property descriptor construction code to construct a list of
    /// properties of the type set as the value of the attribute.
    /// </summary>
    [AttributeUsage(AttributeTargets.Property)]
    public class TypeContainedAttribute : Attribute
    {
        #region Class Member Declarations
        private Type    _typeContainedInCollection;
        #endregion
        /// <summary>
        /// CTor
        /// </summary>
        /// <param name="typeContainedInCollection">The type of the objects contained in the collection
        /// returned by the property this attribute is applied to.</param>
        public TypeContainedAttribute(Type typeContainedInCollection)
        {
            _typeContainedInCollection = typeContainedInCollection;
        }

        #region Class Property Declarations
        /// <summary>
        /// Gets typeContainedInCollection, the type set in the constructor
        /// </summary>
        public Type TypeContainedInCollection
        {
            get
            {
                return _typeContainedInCollection;
            }
        }
        #endregion

    }

    Add the type contained attribute to A's BCollection property:

    /// <summary>
    /// Holds a collection of B objects
    /// which are related to this object through the relation FK_B_A
    /// </summary> 
    [BindableAttribute()]
    [TypeContained(typeof(B))]
    public TList<B> BCollection
    {
     get { return entityData.BCollection; }
     set { entityData.BCollection = value; } 
    }

    Then made the following change to GetItemProperties in ListBase.cs:

    if (listAccessors == null || listAccessors.Length == 0)
    {
       return _propertyCollection;
    }
    else // Expect only one argument representing a child collection
    {
       if (_childCollectionProperties == null)
          _childCollectionProperties = new Dictionary<string,     PropertyDescriptorCollection>();

    // use the last entry in the listAccessors, grab its TypeContainedAttribute and instantiate an instance of
    // the type in that attribute, use that entity instance to produce properties.
       TypeContainedAttribute typeAttribute =
          (TypeContainedAttribute)listAccessors[listAccessors.Length - 1].Attributes[typeof(TypeContainedAttribute)];

       if (typeAttribute == null)
       {
          // not found, not specified, can't determine properties.
          return new PropertyDescriptorCollection(null);
       }

       string typeName = typeAttribute.TypeContainedInCollection.ToString();

       if (_childCollectionProperties.ContainsKey(typeName))
       {
          return _childCollectionProperties[typeName];
       }
       else
       {
          PropertyDescriptorCollection props = EntityHelper.GetBindableProperties(typeAttribute.TypeContainedInCollection);
          _childCollectionProperties.Add(typeName, props);

          return props;
       }
    }


     

    • Post Points: 35
  • 08-03-2006 9:38 PM In reply to

    Re: Problem with ITypedList.GetItemProperties and child collections.

    I had colleague fight his way through the same problem with the telerik grid, so i appreciate you sending this, we will look at this tonight.

    Thanks for your contribution.

    Robert Hinojosa
    -------------------------------------
    Member of the Codesmith Tools, .netTiers, teams
    http://www.nettiers.com
    -------------------------------------
    • Post Points: 35
  • 08-04-2006 2:06 PM In reply to

    • jasona941
    • Not Ranked
    • Joined on 08-02-2006
    • Posts 4
    • Points 110

    Re: Problem with ITypedList.GetItemProperties and child collections.

    I'm happy to oblige -- I think you guys are doing some great work with this.

    In the past, I've avoided data-binding controls like the plague. But the Microsoft side of the fence seems to have come a long way to providing a useable data binding implementation (at least for me). For me, having .netTiers incorporate the Enterprise Library ABs was the best part of the cake... if this object data binding is as useable (for my applications) as it appears then that would be the icing.

    • Post Points: 35
  • 09-06-2006 5:31 AM In reply to

    Re: Problem with ITypedList.GetItemProperties and child collections.

    Hi

    I have also had some problems related to the implementation of ListBase<T>.GetItemProperties.  In my scenario I had a TList<Album> with a child collection TList<Track>.  I had this TList<Album> bound to a combobox and the TList<Track> bound to a datagridview.  This was hooked up as recommended in microsoft docs with a bindingsource hooked up correctly to manage synchronization.  I know this was hooked up correctly as I tested doing the same with normal List<TestClass> with child collection of List<TestChildClass> and all worked fine.

    With the TList implementation the datagridview displayed the correct amount of rows for the child collection but no data.

    The change I made to correct this behavior was to change the line:

    PropertyDescriptorCollection props = EntityHelper.GetBindableProperties(listAccessors[0].PropertyType);

    to

    PropertyDescriptorCollection props = EntityHelper.GetBindableProperties(listAccessors[0].PropertyType.GetGenericArguments()[0]);

    In this way returning the properties of the child collections generic type argument (in this case Track) instead of the properties of TList itself.

    As I am very new to nettiers and data binding I would really appreciate any feedback on whether this is a necessary change to make or if I’ve missed the point completely.

    I must say I actually don’t understand the need to implement ITypedList interface very well as it seems that the bindingsource (I think) must be able to offer a default implementation that seems to work fine as is? Any insight here would be great.

    Thanks

    Duncan

    • Post Points: 5
Page 1 of 1 (4 items) | RSS
Copyright © 2008 CodeSmith Tools, LLC
Powered by Community Server (Commercial Edition), by Telligent Systems