Grouping with dynamically generated types

4 posts, 1 answers
  1. Greg
    Greg avatar
    8 posts
    Member since:
    Dec 2007

    Posted 30 Jul 2009 Link to this post

    In my application I need to bind RadGridViews to tabular data exposed via web services where the columns may not be known at compile time. In ASP.NET the solution was to return a DataSet and bind to a DataTable, and this worked very well. In Silverlight, there is no DataSet (DataSets are proxied as instances of ArrayOfXElement which contains a couple of XML fields), so to compensate, I parse the ArrayOfXElement object and extract the columns and type data from the XML contained therein. I take this data and build a dynamic type using System.Emit namespace. The result is a type which contains a public get/set property corresponding to each column in the source datatable, with a matching type. I then populate a collection of these types using the xml data. I end up with IEnumerable<object> which I then set to the RadGridView.ItemSource, and everything works fine. The problem is, the GroupDescriptor.Version field cannot seem to be used to point to one of these dynamic properties, whereas the GridViewDataColumn.DataMemberPath has no issues in this regard. When the name of a dynamic property is specified in the GroupDescriptor.Version field, it results in an exception being thrown when ItemSource is set. See below error (note that Version is the name of the dynamic property I'm trying to group on). The source code used to generate the dynamic type is included below for interest, although the code works perfectly. The key question is why does binding the actual data to the grid columns work fine with dynamic types, but grouping does not? They should both use reflection, right?

    Thanks
    Greg

    Webpage error details

    User Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; WOW64; Trident/4.0; SLCC1; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.5.21022; .NET CLR 3.0.30618; .NET CLR 3.5.30729; MS-RTC LM 8; MS-RTC EA 2)
    Timestamp: Thu, 30 Jul 2009 17:31:20 UTC

    Message: Unhandled Error in Silverlight 2 Application Invalid property or field - 'Version' for type: Object   at Telerik.Windows.Data.Expressions.MemberAccessTokenExtensions.CreateMemberAccessExpression(IMemberAccessToken token, Expression instance)
       at Telerik.Windows.Data.Expressions.ExpressionFactory.MakeMemberAccess(Expression instance, String memberName)
       at Telerik.Windows.Data.Expressions.ExpressionFactory.MakeMemberAccess(Expression instance, String memberName, Boolean liftMemberAccessToNull)
       at Telerik.Windows.Data.Expressions.PropertyAccessExpressionBuilder.CreateMemberAccessExpression()
       at Telerik.Windows.Data.Expressions.MemberAccessExpressionBuilderBase.CreateLambdaExpression()
       at Telerik.Windows.Data.Expressions.GroupDescriptorExpressionBuilder.CreateGroupByExpression()
       at Telerik.Windows.Data.Expressions.GroupDescriptorExpressionBuilderBase.CreateQuery()
       at Telerik.Windows.Data.Expressions.GroupDescriptorCollectionExpressionBuilder.CreateQuery()
       at Telerik.Windows.Data.QueryableExtensions.GroupBy(IQueryable source, GroupDescriptorCollection groupDescriptors)
       at Telerik.Windows.Data.QueryableCollectionView.CreateView()
       at Telerik.Windows.Data.QueryableCollectionView.get_QueryableView()
       at Telerik.Windows.Data.QueryableCollectionView.CreateInternalList()
       at Telerik.Windows.Data.QueryableCollectionView.get_InternalList()
       at Telerik.Windows.Data.QueryableCollectionView.GetEnumerator()
       at Telerik.Windows.Data.RecordFactory.<CreateRecordsForGroupRecord>d__0.MoveNext()
       at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
       at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
       at Telerik.Windows.Controls.GridView.GridViewDataControl.PopulateRecords()
       at Telerik.Windows.Controls.GridView.GridViewDataControl.LoadData()
       at Telerik.Windows.Controls.GridView.GridViewDataControl.<>c__DisplayClass3c.<Bind>b__3b()
       at Telerik.Windows.Controls.CursorManager.PerformTimeConsumingOperation(FrameworkElement frameworkElement, Action action)
       at Telerik.Windows.Controls.GridView.GridViewDataControl.Bind(Object newValue)
       at Telerik.Windows.Controls.GridView.GridViewDataControl.OnItemsSourceChanged(Object oldValue, Object newValue)
       at Telerik.Windows.Controls.DataControl.OnItemsSourcePropertyChanged(DependencyObject origin, DependencyPropertyChangedEventArgs args)
       at Telerik.Windows.PropertyMetadata.<>c__DisplayClass1.<Create>b__0(DependencyObject d, DependencyPropertyChangedEventArgs e)
       at System.Windows.DependencyObject.RaisePropertyChangeNotifications(DependencyProperty dp, Object newValue, Object oldValue)
       at System.Windows.DependencyObject.SetValueInternal(DependencyProperty dp, Object value, Boolean allowReadOnlySet, Boolean isSetByStyle, Boolean isSetByBuiltInStyle, PropertyInvalidationReason reason)
       at System.Windows.DependencyObject.SetValueInternal(DependencyProperty dp, Object value)
       at System.Windows.DependencyObject.SetValue(DependencyProperty dp, Object value)
       at Telerik.Windows.Controls.DataControl.set_ItemsSource(Object value)
       at GFSChangeSilverlight.ChangeUI.reportSvc_ExecuteQueryCompleted(Object sender, ExecuteQueryCompletedEventArgs e)
       at GFSChangeSilverlight.ReportService.ReportServiceSoapClient.OnExecuteQueryCompleted(Object state)
    Line: 1
    Char: 1
    Code: 0
    URI: http://localhost/gfschange/Change2.aspx?mode=rfc&id=24436



    private

     

    static Type CreateType(IEnumerable<XElement> columnDefinitions)

     

    {

     

    AppDomain myDomain = AppDomain.CurrentDomain;

     

     

    AssemblyName myAsmName = new AssemblyName("MyAssembly");

     

    System.Reflection.Emit.

    AssemblyBuilder myAssembly = myDomain.DefineDynamicAssembly(myAsmName, AssemblyBuilderAccess.Run);

     

     

    ModuleBuilder myModule = myAssembly.DefineDynamicModule(myAsmName.Name);

     

     

    TypeBuilder myType = myModule.DefineType("DataSource", TypeAttributes.Public);

     

     

    foreach (XElement col in columnDefinitions)

     

    {

     

    XAttribute typeAttribute = col.Attributes().First<XAttribute>(a => a.Name.LocalName == "type");

     

     

    Type propertyType;

     

     

    switch (typeAttribute.Value)

     

    {

     

    case "xs:dateTime":

     

    propertyType =

    typeof(Nullable<DateTime>);

     

     

    break;

     

     

    case "xs:string":

     

    propertyType =

    typeof(String);

     

     

    break;

     

     

    case "xs:int":

     

    propertyType =

    typeof(Nullable<int>);

     

     

    break;

     

     

    default:

     

     

    throw new Exception("Unexpected type attribute value: " + typeAttribute.Value);

     

    }

     

    XAttribute nameAttribute = col.Attributes().First<XAttribute>(a => a.Name.LocalName == "name");

     

     

    string propertyName = nameAttribute.Value;

     

     

    FieldBuilder exField = myType.DefineField("_" + propertyName, propertyType, FieldAttributes.Public);

     

     

    PropertyBuilder exProperty = myType.DefineProperty(propertyName, PropertyAttributes.None, propertyType, Type.EmptyTypes);

     

     

    MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;

     

     

    MethodBuilder exGetMethod = myType.DefineMethod("get_" + propertyName,

     

    getSetAttr,

    propertyType,

     

    Type.EmptyTypes);

     

     

    ILGenerator getIlgen = exGetMethod.GetILGenerator();

     

    getIlgen.Emit(

    OpCodes.Ldarg_0);

     

    getIlgen.Emit(

    OpCodes.Ldfld, exField);

     

    getIlgen.Emit(

    OpCodes.Ret);

     

    exProperty.SetGetMethod(exGetMethod);

     

    MethodBuilder exSetMethod = myType.DefineMethod("set_" + propertyName,

     

    getSetAttr,

     

    null,

     

     

    new Type[] { propertyType });

     

     

    ILGenerator setIlgen = exSetMethod.GetILGenerator();

     

    setIlgen.Emit(

    OpCodes.Ldarg_0);

     

    setIlgen.Emit(

    OpCodes.Ldarg_1);

     

    setIlgen.Emit(

    OpCodes.Stfld, exField);

     

    setIlgen.Emit(

    OpCodes.Ret);

     

    exProperty.SetSetMethod(exSetMethod);

    }

     

    return myType.CreateType();

     

    }

     

     

  2. Answer
    Vlad
    Admin
    Vlad avatar
    11100 posts

    Posted 31 Jul 2009 Link to this post

    Hello Greg,

    You can use my DataTable and everything will work as expected :)

    Kind regards,
    Vlad
    the Telerik team

    Instantly find answers to your questions on the new Telerik Support Portal.
    Check out the tips for optimizing your support resource searches.
  3. E
    E avatar
    1 posts
    Member since:
    Sep 2010

    Posted 28 Sep 2010 Link to this post

    Hello Greg. Currently I'm having the same problem . Do you have a sample project with the solution you applied?
    Thank you very much,

    Regards,
  4. jfkrueger
    jfkrueger avatar
    269 posts
    Member since:
    Jul 2012

    Posted 26 Nov 2011 Link to this post

    That's great but I would still like to hear an answer to the original question without having to completely restructure my data.
Back to Top