Powered by MSDN

US - English
NEW! Silverlight 5 is available Learn More

  • Raag80

    Raag80

    Member

    396 Points

    91 Posts

    Re: Re: Creating dynamic List<> for binding to Datagrid

    Mar 13, 2009 11:16 AM | LINK

    Hi,

    I was having the same issue. as you have....then i found a article and which i have pasted here....i have implemeted with live data and its works

    If you want to define the number and the type of Silverlight DataGrid columns at runtime you can use the following approach. The technique can actually be used not only for Silverlight but also anywhere where you have to transform IDictionary (for example Dictionary or Hashtable, SortedDictionary etc) into anonymous typed object with each dictionary key turned into an object property.

    You may say that this way I can violate the object constraints. For example each IDictionary inside IEnumerable can have different set of keys. And to a certain degree I can agree with that and if you rely on the data to come from a third party I wouldn’t recommend this approach or at least I would advice you to validate each IEnumerable entry before binding it to the control. But if you have a complete control on the transformation of the data – this is definitely a good approach. You can think of this as a way to use C# as a dynamic language. In the current solution I check the keys in the first entry of IEnumerable and if the second has more keys they will be ignored or if it has less the default values will be passed (null, Guid.Empty etc.)

    So here is how your code can look. This is the code behind of an Xaml page:

    public partial class Page : UserControl
        {
            public Page()
            {
                InitializeComponent();

                this.theGrid.Columns.Add(
                            new DataGridTextColumn
                            {
                                Header = "ID",
                                Binding = new Binding("ID")
                            });
                this.theGrid.Columns.Add(
                            new DataGridTextColumn
                            {
                                Header = "Name",
                                Binding = new Binding("Name")
                            });
                this.theGrid.Columns.Add(
                            new DataGridTextColumn
                            {
                                Header = "Index",
                                Binding = new Binding("Index")
                            });
                this.theGrid.Columns.Add(
                            new DataGridTextColumn
                            {
                                Header = "Is Even",
                                Binding = new Binding("IsEven")
                            });
                this.theGrid.ItemsSource = GenerateData().ToDataSource();
            }

            public IEnumerable GenerateData()
            {
                for(var i = 0; i < 15; i++)
                {
                    var dict = new Dictionary<string, object>();
                    dict["ID"] = Guid.NewGuid();
                    dict["Name"] = "Name_" + i;
                    dict["Index"] = i;
                    dict["IsEven"] = ( i%2 == 0);
                    yield return dict;
                }
            }
        }Or in Visual Basic:

        ...
    Public Function GenerateData() As IEnumerable(Of IDictionary)
        Dim list As New List(Of IDictionary)()
        For i As Integer = 0 To 9
            Dim dict As IDictionary = New Dictionary(Of String, Object)()
            dict("ID") = Guid.NewGuid()
            dict("Name") = "Name_" & i.ToString()
            dict("Index") = i
            dict("IsEven") = (i Mod 2 = 0)
            list.Add(dict)
        Next
        Return list
    End Function

        The Xaml can be as simple as that:

        "LayoutRoot" Background="White">
           
    "theGrid"
                    Grid.Column="0"
                    Grid.Row="0"
                    AutoGenerateColumns="False">
           
        As you can see the IEnumerable of IDictionary has no ToDataSource() method so we have to define this extension method and there is where the magic happens.


    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Reflection;
    using System.Reflection.Emit;
    using System.Text;
    using System.Text.RegularExpressions;
    using System.Windows.Browser;

    namespace com.bodurov
    {

        public static class DataSourceCreator
        {
            private static readonly Regex PropertNameRegex =
                    new Regex(@"^[A-Za-z]+[A-Za-z1-9_]*$", RegexOptions.Singleline);

            private static readonly Dictionary<string, Type> _typeBySigniture =
                    new Dictionary<string,Type>();


            public static IEnumerable ToDataSource(this IEnumerable list)
            {
                IDictionary firstDict = null;
                bool hasData = false;
                foreach (IDictionary currentDict in list)
                {
                    hasData = true;
                    firstDict = currentDict;
                    break;
                }
                if (!hasData)
                {
                    return new object[] { };
                }
                if (firstDict == null)
                {
                    throw new ArgumentException("IDictionary entry cannot be null");
                }

                string typeSigniture = GetTypeSigniture(firstDict);

                Type objectType = GetTypeByTypeSigniture(typeSigniture);

                if(objectType == null)
                {
                    TypeBuilder tb = GetTypeBuilder(typeSigniture);

                    ConstructorBuilder constructor =
                                tb.DefineDefaultConstructor(
                                            MethodAttributes.Public |
                                            MethodAttributes.SpecialName |
                                            MethodAttributes.RTSpecialName);


                    foreach (DictionaryEntry pair in firstDict)
                    {
                        if (PropertNameRegex.IsMatch(Convert.ToString(pair.Key), 0))
                        {
                            CreateProperty(tb,
                                            Convert.ToString(pair.Key),
                                            GetValueType(pair.Value));
                        }
                        else
                        {
                            throw new ArgumentException(
                                        @
    "Each key of IDictionary must be
                                    alphanumeric and start with character."
    );
                        }
                    }
                    objectType = tb.CreateType();

                    _typeBySigniture.Add(typeSigniture, objectType);
                }

                return GenerateEnumerable(objectType, list, firstDict);
            }

            private static Type GetTypeByTypeSigniture(string typeSigniture)
            {
                Type type;
                return _typeBySigniture.TryGetValue(typeSigniture, out type) ? type : null;
            }

            private static Type GetValueType(object value)
            {
                return value == null ? typeof (object) : value.GetType();
            }

            private static string GetTypeSigniture(IDictionary firstDict)
            {
                StringBuilder sb = new StringBuilder();
                foreach (DictionaryEntry pair in firstDict)
                {
                    sb.AppendFormat("_{0}_{1}", pair.Key, GetValueType(pair.Value));
                }
                return sb.ToString().GetHashCode().ToString().Replace("-", "Minus");
            }

            private static IEnumerable GenerateEnumerable(
                     Type objectType, IEnumerable list, IDictionary firstDict)
            {
                var listType = typeof(List<>).MakeGenericType(new[] { objectType });
                var listOfCustom = Activator.CreateInstance(listType);

                foreach (var currentDict in list)
                {
                    if (currentDict == null)
                    {
                        throw new ArgumentException("IDictionary entry cannot be null");
                    }
                    var row = Activator.CreateInstance(objectType);
                    foreach (DictionaryEntry pair in firstDict)
                    {
                        if (currentDict.Contains(pair.Key))
                        {
                            PropertyInfo property =
                                objectType.GetProperty(Convert.ToString(pair.Key));
                            property.SetValue(
                                row,
                                Convert.ChangeType(
                                        currentDict[pair.Key],
                                        property.PropertyType,
                                        null),
                                null);
                        }
                    }
                    listType.GetMethod("Add").Invoke(listOfCustom, new[] { row });
                }
                return listOfCustom as IEnumerable;
            }

            private static TypeBuilder GetTypeBuilder(string typeSigniture)
            {
                AssemblyName an = new AssemblyName("TempAssembly" + typeSigniture);
                AssemblyBuilder assemblyBuilder =
                    AppDomain.CurrentDomain.DefineDynamicAssembly(
                        an, AssemblyBuilderAccess.Run);
                ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");

                TypeBuilder tb = moduleBuilder.DefineType("TempType" + typeSigniture
                                    , TypeAttributes.Public |
                                    TypeAttributes.Class |
                                    TypeAttributes.AutoClass |
                                    TypeAttributes.AnsiClass |
                                    TypeAttributes.BeforeFieldInit |
                                    TypeAttributes.AutoLayout
                                    , typeof(object));
                return tb;
            }

            private static void CreateProperty(
                            TypeBuilder tb, string propertyName, Type propertyType)
            {
                FieldBuilder fieldBuilder = tb.DefineField("_" + propertyName,
                                                            propertyType,
                                                            FieldAttributes.Private);


                PropertyBuilder propertyBuilder =
                    tb.DefineProperty(
                        propertyName, PropertyAttributes.HasDefault, propertyType, null);
                MethodBuilder getPropMthdBldr =
                    tb.DefineMethod("get_" + propertyName,
                        MethodAttributes.Public |
                        MethodAttributes.SpecialName |
                        MethodAttributes.HideBySig,
                        propertyType, Type.EmptyTypes);

                ILGenerator getIL = getPropMthdBldr.GetILGenerator();

                getIL.Emit(OpCodes.Ldarg_0);
                getIL.Emit(OpCodes.Ldfld, fieldBuilder);
                getIL.Emit(OpCodes.Ret);

                MethodBuilder setPropMthdBldr =
                    tb.DefineMethod("set_" + propertyName,
                      MethodAttributes.Public |
                      MethodAttributes.SpecialName |
                      MethodAttributes.HideBySig,
                      null, new Type[] { propertyType });

                ILGenerator setIL = setPropMthdBldr.GetILGenerator();

                setIL.Emit(OpCodes.Ldarg_0);
                setIL.Emit(OpCodes.Ldarg_1);
                setIL.Emit(OpCodes.Stfld, fieldBuilder);
                setIL.Emit(OpCodes.Ret);

                propertyBuilder.SetGetMethod(getPropMthdBldr);
                propertyBuilder.SetSetMethod(setPropMthdBldr);
            }
        }




    }

     
    Regards,
    Raag

    If it is Solved your problem then mark as answer bcoz other with same question can benefit.....