Powered by MSDN

US - English
NEW! Silverlight 5 is available Learn More

How to Display DataSet in Silverlight DataGrid RSS

169 replies

Last post May 17, 2012 05:22 PM by demmith2

(0)
  • sladapter

    sladapter

    All-Star

    43609 Points

    7910 Posts

    How to Display DataSet in Silverlight DataGrid

    May 27, 2008 05:25 PM | LINK

    A lot of people have asked this question. The answer is that there is no direct way.

    Current Silverlight does not support DataSet object. I was hoping to see DataSet support in beta 2, but according to people from Microsoft (http://silverlight.net/forums/p/16297/54531.aspx#54531) that DataSet support is not likely even in version 2 final release.

    So what should we do? In our application we hold our Data in DataSet from the Data tier to the UI tier. We don't want to covert it to a list of object with pre-defined properties in WCF before we pass it to Silverlight. In our case that is not even possible. In our application almost every SQL is dynamically generated.

    One solution is to pass the DataSet Column Information and DataSet XML to the silverlight. On the Silverlight side we build a Dynamic Data Object based on those data with functions provided by System.Reflection.Emit namespace. Then we bind the List of dynamically build DataObject to the DataGrid. The Dynamic Data Object will have one property for each column in the DataSet with the same DataType.

    Because we have the Column Information besides the Data,  binding to the DataGrid can be very flexible. I can set AutoGeneratedColumn = true so it display all the Data in the DataSet or I can dynamically generate columns I want to display.


    Here is my code in case anybody wants to try:

    Steps to Test:

    1) Download the Source from http://cid-9cffd385fd75195b.skydrive.live.com/self.aspx/Silverlight/DataSetInDataGrid.zip

    2) Open the solution file in VS 2008

    3) Find GetData.cs in DataSetInDataGrid.Silverlight project and change the Database connection string to a connection string that connects to your SQL server database.

         private const string connectionString = @"Data Source=LOCALHOST;Initial Catalog=Northwind;Integrated Security=True;";  // change this


    4) Set start page to Default.html in DataSetInDataGrid.Silverlight_Web project. Build and run the application.

    5) Type in any SQL statement to do a query to your database. The returning data should be displayed in the DataGrid automatically.

    6) Implement your UpdateDataSet function in the GetData.cs to update the Data in the DataSet to DB (such as build Update sql statement based on the current data in the DataSet).

     

    Let me know if you see any problems.

     

     


           

     

     

     

     

     

     

     

     


     

     

     

    Sally Xu
    Software Engineer
    Aprimo, Inc

    Please remember to mark the replies as answers if they answered your question
  • slhungry

    slhungry

    Member

    44 Points

    30 Posts

    Re: How to Display DataSet in Silverlight DataGrid

    Jun 10, 2008 04:21 AM | LINK

    wow looks like alot of deep heavy stuff to get this working, but i'm glad u have a solution.  i converted it over to beta2 with a few tweaks and works great, but only problem is i can't get it to sort by clicking on the columns.  beta2 supports CanUserReorderColumns property for datagrid but when i click on it, it gives me an error.  "SortDescription's property name is invalid"

    it would be so awesome if i can get sorting too, any idea?

  • samcov

    samcov

    Participant

    1673 Points

    719 Posts

    Re: How to Display DataSet in Silverlight DataGrid

    Jun 10, 2008 07:00 AM | LINK

    What you want is to be able to dynamically build a DataGrid in SilverLight with ANY data you may deliver from the server.  The data could be an Array of records, a DataSet, XML, or weakly typed JSON, it doesn't matter.  Here is the code I use to do that, and also dynamically create the columns.  I found this code somewhere, but I don't remember where, but it works great.

    Here is the code that creates the DataGrid:
        public partial class DynamicGrid : UserControl
        {
            public DynamicGrid()
            {
                InitializeComponent();

                Canvas.SetLeft(butt, 500);

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

            public IEnumerable<IDictionary> GenerateData()
            {
                for (var i = 0; i < 1000; i++)
                {
                    var dict = new Dictionary<string, object>();
                    dict.Add("ID", Guid.NewGuid());
                    dict.Add("Name", "Name_" + i);
                    dict.Add("Index", i);
                    dict.Add("IsEven", i % 2 == 0);
                    yield return dict;
                }
            }
        }

    To make this work, you need the following Extension Method:
        public static class DataSourceCreator
        {
            private static readonly Regex PropertNameRegex =
                    new Regex(@"^[A-Za-z]+[A-Za-z1-9_]*$", RegexOptions.Singleline);

            public static object[] ToDataSource(this IEnumerable<IDictionary> 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");
                }

                Type objectType = null;

                TypeBuilder tb = GetTypeBuilder(list.GetHashCode());

                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),
                                        pair.Value == null ?
                                                    typeof(object) :
                                                    pair.Value.GetType());
                    }
                    else
                    {
                        throw new ArgumentException(
                                    @"Each key of IDictionary must be
                                    alphanumeric and start with character.");
                    }
                }
                objectType = tb.CreateType();
                return GenerateArray(objectType, list, firstDict);
            }

            private static object[] GenerateArray(Type objectType, IEnumerable<IDictionary> list, IDictionary firstDict)
            {
                var itemsSource = new List<object>();
                foreach (var currentDict in list)
                {
                    if (currentDict == null)
                    {
                        throw new ArgumentException("IDictionary entry cannot be null");
                    }
                    object 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);
                        }
                    }
                    itemsSource.Add(row);
                }
                return itemsSource.ToArray();
            }

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

                TypeBuilder tb = moduleBuilder.DefineType("TempType" + code
                                    , 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);
            }
        }

    This will yield the following Grid:

  • samcov

    samcov

    Participant

    1673 Points

    719 Posts

    Re: How to Display DataSet in Silverlight DataGrid

    Jun 10, 2008 07:09 AM | LINK

    I posted all that, and then later saw your link, which is a very similar solution.

    I wish I could remember where I got that code, but it works, and is quite fast.

    Sam...

  • sladapter

    sladapter

    All-Star

    43609 Points

    7910 Posts

    Re: How to Display DataSet in Silverlight DataGrid

    Jun 10, 2008 01:28 PM | LINK

    slhungry

    wow looks like alot of deep heavy stuff to get this working, but i'm glad u have a solution.  i converted it over to beta2 with a few tweaks and works great, but only problem is i can't get it to sort by clicking on the columns.  beta2 supports CanUserReorderColumns property for datagrid but when i click on it, it gives me an error.  "SortDescription's property name is invalid"

    it would be so awesome if i can get sorting too, any idea?

    Because I have not put any sort code in that sample. Also how to do sort really depend on how you want it. Do you want to go back to the database to re-run the query so your sort really means against all the data or you just want to sort with the current dataset. You can implement that part yourself to fit your need. It should not be that difficult.

     


     

    Sally Xu
    Software Engineer
    Aprimo, Inc

    Please remember to mark the replies as answers if they answered your question
  • samcov

    samcov

    Participant

    1673 Points

    719 Posts

    Re: How to Display DataSet in Silverlight DataGrid

    Jun 11, 2008 08:21 AM | LINK

    samcov

    I wish I could remember where I got that code, but it works, and is quite fast.

    Well, I can stop wishing.  Here is the article I got this from.

    <script src="http://www.google-analytics.com/urchin.js" type=text/javascript> </script> <script type=text/javascript> _uacct = "UA-2223138-1"; urchinTracker(); </script>
  • batmansilver

    batmansilver

    Member

    61 Points

    58 Posts

    Re: How to Display DataSet in Silverlight DataGrid

    Jun 20, 2008 01:40 AM | LINK

    Hello Sladaper,

    As your instruction, I found this post and I tried to download your demo from your link.

    When I open it I got some errors like the following...

    1. I cannot find the GetData.cs in DataSetInDataGrid.Silverlight project.

    2. In the reference of SL project, there are warning icons on System.Windows.Controls.Data, System.Windows.Controls.Data. So I tried to remove and add reference again. But I got the errors:

    Library project file cannot specify ApplicationDefinition element.

    The project file contains a property value that is not valid


    I'm using Silverlight 2 Beta 1. Is this the Silverlight 2 Beta 2 project? if so how can I use it in Beta 1?

    Thank you. 

    Thanks and Best Regards
  • sladapter

    sladapter

    All-Star

    43609 Points

    7910 Posts

    Re: How to Display DataSet in Silverlight DataGrid

    Jun 20, 2008 02:01 AM | LINK

    It used to be beta1 project. But I updated it after beta2 was released. I don't know if I can still find the original zip file. 

    Why are you still using beta1?

     

    Sally Xu
    Software Engineer
    Aprimo, Inc

    Please remember to mark the replies as answers if they answered your question
  • batmansilver

    batmansilver

    Member

    61 Points

    58 Posts

    Re: How to Display DataSet in Silverlight DataGrid

    Jun 20, 2008 02:12 AM | LINK

    I have many small projects in Beta 1 and now I don't have enought time to convert (also I must look in detail of Beta 2 to convert...).

    If you can give me the version in Beta 1, that'll be very good. But I don't want you to cost much time to find back so it's ok. Maybe I will try another way.

    Thank you. 

    Thanks and Best Regards
  • sladapter

    sladapter

    All-Star

    43609 Points

    7910 Posts

    Re: How to Display DataSet in Silverlight DataGrid

    Jun 20, 2008 02:41 AM | LINK

    Sorry, I do not have the original file any more.

    For converting from beta 1 to beta 2, it will take some effort. It took me a few days to fully convert my projects and have every issues resolved. But issues mainly come from a few areas. MouseDownEvent break for many controls is one, WCF Service cross-domain file change is another. Other than that, I just need to fix some Xaml and code to use the new syntax.

    But you have to do it anyway. Because now all the code samples are in beta2. All the demo sites are updated to beta2. Most discussions here are about beta2. You have no other choice.

     

     

     

    Sally Xu
    Software Engineer
    Aprimo, Inc

    Please remember to mark the replies as answers if they answered your question