none
How to Display DataSet in Silverlight DataGrid

    Question

  • 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.

     

     


           

     

     

     

     

     

     

     

     


     

     

     

    Tuesday, May 27, 2008 1:25 PM

All replies

  • 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?

    Tuesday, June 10, 2008 12:21 AM
  • 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:

    Tuesday, June 10, 2008 3:00 AM
  • 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...

    Tuesday, June 10, 2008 3:09 AM
  • 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.

     


     

    Tuesday, June 10, 2008 9:28 AM
  • 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.

     
    This was indeed an impressive solution with great performance.
     
    While you're there, he also has a sweet wrapper on the DispatcherTimer, to create a setTimeout function in SL, like javascript.  The direct link is below.
     
     
    Sam...
    _uacct = "UA-2223138-1"; urchinTracker();
    Wednesday, June 11, 2008 4:21 AM
  • 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. 

    Thursday, June 19, 2008 9:40 PM
  • 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?

     

    Thursday, June 19, 2008 10:01 PM
  • 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. 

    Thursday, June 19, 2008 10:12 PM
  • 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.

     

     

     

    Thursday, June 19, 2008 10:41 PM
  •  

    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...

    Sam,

    Have you tried your Dynamic Grid code in beta 2? Does the new DataGrid built-in Sort function work in your grid? Is does not work on mine. I think it's because we bind the ItemsSource to a List<object> so Linq won't work on this dynamically build object list.

    I looked at the code you posted, it's basically the same idea to Dynamically build a object using functions/objects provided by System.Reflection.Emit name space. So I'm wondering if the sort function works for you.

    I don't know if I can figure out a way to make Linq work on those list.

    Thanks!

     

    Never mind. I got it working now. Thanks for that link you provided.

     

     

     

    Friday, June 20, 2008 2:36 PM
  •  

    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?

     slhungry,

    Get the latest, sorting is working now.

     

    Friday, June 20, 2008 4:16 PM
  • The code works well in Beta 2, but you're right, the sorting doesn't work.

    I'll take a look at your code.

    Thanks!

    Saturday, June 21, 2008 4:11 AM

  • Tuesday, July 08, 2008 11:35 AM
  • Hi Sladapter,

    Thanks for your code. Its working fine.

     I have tried to reproduce it. But I am not able to get the results.

    I am getting following error.

    The remote server returned an unexpected response: (404) Not Found.

    Could you please help me with this.

    Thanks and Regards,

    Rams

    Tuesday, July 08, 2008 11:36 AM
  • That must be WCF connection error. You can remove the Service Reference first then re-add it back.  If it still not working let me know. I'll help you to figure out.

     

    Tuesday, July 08, 2008 11:54 AM
  •  Hi Sladapter,

    Thanks for your reply.

    I have done that. But no success.

    I have noticed one chage ServiceReferences.ClientConfig file

    In ur code it is 

    <configuration>
        <system.serviceModel>
            <bindings>
                <basicHttpBinding>
                    <binding name="LargeSize_IGetData" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647">
                        <security mode="None" />
                    </binding>
                </basicHttpBinding>
            </bindings>
            <client>
                <endpoint address="http://localhost:3317/DataSetInDataGrid.Silverlight_Web/GetData.svc"
                    binding="basicHttpBinding" bindingConfiguration="LargeSize_IGetData"
                    contract="DataSetInDataGrid.Silverlight.GetDataService.IGetData"
                    name="LargeSize_IGetData" />
            </client>
        </system.serviceModel>
    </configuration>

    In my code it generated like this

    <configuration>
        <system.serviceModel>
            <bindings>
                <wsHttpBinding>
                    <binding name="WSHttpBinding_IGetData" closeTimeout="00:01:00"
                        openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
                        bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
                        maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
                        messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
                        allowCookies="false">
                        <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                            maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                        <reliableSession ordered="true" inactivityTimeout="00:10:00"
                            enabled="false" />
                        <security mode="Message">
                            <transport clientCredentialType="Windows" proxyCredentialType="None"
                                realm="" />
                            <message clientCredentialType="Windows" negotiateServiceCredential="true"
                                algorithmSuite="Default" establishSecurityContext="true" />
                        </security>
                    </binding>
                </wsHttpBinding>
            </bindings>        
        </system.serviceModel>
    </configuration>

    I guess it is the problem.

    Thanks,

    Rams.

     

     

     

    Tuesday, July 08, 2008 12:17 PM
  • Hi Sladapter,

    My problem was solved.

    I have changed the  <system.serviceModel> in my web.config file.

    Now its working fine.

    Thank you very much for your support.

    Rams.

     

    Tuesday, July 08, 2008 1:47 PM
  • WCF Service cross-domain file change is another
     

    I was going to ask what you meant by that, but was able to track it down myself.  In case it might save anyone some time, clientaccesspolicy.xml now needs the bolded "http-request-headers" attribute.  Here's what I have for the most generic clientaccesspolicy.xml as of Silverlight 2 Beta 2.

    <?xml version="1.0" encoding="utf-8"?>
       <access-policy>
         <cross-domain-access>
           <policy>
             <allow-from http-request-headers="*">
               <domain uri="*"/>
             </allow-from>
             <grant-to>
               <resource path="/" include-subpaths="true"/>
             </grant-to>
           </policy>
         </cross-domain-access>
       </access-policy>
    Thursday, July 10, 2008 9:20 AM
  • Hi Sladapter,

    I tried your demo. It's work fine but I have some questions.
    #1. I have a class or struct in SL. This class will receive the information the user input in SL project (eg. Student - a custom data) and in my asp.net project I have create a WCF webservice to save the student information to database but it must receive from the Student class in SL project so how to send this information as a parameter to the webservice in asp.net.

    #2. the same as the first one, if the webservice return a class defined in asp.net project or the database object like DataTable, DataRow,... so how to use the return value in Silverlight?

    #3. I see you have the DynamicDataBuilder class. I don't understand the code but I understand it is for using the data return from webservice to use in Silverlight.
    But is this class is general solution for receiving any custom data ? can I use it in my case to bind to my SL usercontrol...? if not, please tell me how to archive this to use in my specific case. I really want to know because I need to do SCUD in SL but in the old way using SqlServer data provider.

    Could you explain or give me guide material what I need to know about transfer defined data between SL and asp.net and use the transfer data in both SL and asp.net side???
    Waiting for the reply!!!

    Thank you and Regard.

    John.


     

    Thursday, July 10, 2008 9:36 AM
  • John,

    My solution is mainly for generic data display which means I do not have or I do not I want a pre-defined data object. Because our data is very dynamic.  We have more than 1000 tables which I do not want to define object for each of them. Plus our tables also can be customized which means the table fields could be changed/added/removed by customer(Company who brought our application) later. The SQL for query data is also very dynamic. Each user can set filter based on different field and can select different column as they want.

    That is why I have to create a dynamic data object based on the DataSet data and column infomation. In real case my column infomation is really comming from our meta data which describe each field of our object. Because Silverlight does not support DataSet/DataTable, so I can not pass back DataSet directly. I have to pass back serialized Xml string to Silverlight then convert it to a list of DynamicDataObject. When I try to save data, I covert my List of DynamicDataObject to XML string and pass it back to WCF. On the WCF I process this Xml and do the update to database accordingly.

    If you have a pre-defined data object such as Student class and your application is not as complicated as ours,  then you do not need to use this solution. Use LinQ + Entity model + WCF service or use .Net DataService might be better for your case. By using that, your code would be easy to program and understand.

    If you still like to use the old way of SQL + DataSet  to access your data, then you can convert the DataSet to your Student object on WCF code before you return it to Silverlight. You need to move your Student class defination to the Service side. Then just pass populated Student List back to Silverlight. Then bind the list to your DataGrid or other controls.

    There are a lot of tutorials on this subject. Take a look at them. Here is one  http://silverlight.net/learn/tutorials/sqldatagrid.aspx

     

     

     

     

    Thursday, July 10, 2008 11:24 AM
  • Hi Sladapter,

    I really thank you for your detail explaination. It will help me alot because I am using SqlServer data provider and store procedure and of course my data is not complicated. I'm trying to test by making 2 same class of pre-defined object in SL and asp.net about Student so I can test if this way will work.

    Thank you and Regard,

    John. 

    Thursday, July 10, 2008 12:45 PM
  • Hi Sladapter,

    I have a small doubt.

    In your code after getting details from database we are converting them to list of objects using the following line. Right?

    theGrid.ItemsSource = DynamicDataBuilder.GetDataList(e.Result);

    But in my case i need to access induvidual recored.

    for example, I am retrieving user details and I want display the first user's name.

    I have tried like this

    • created a class named User
    • List<User> UserDetails =(List<User>)DynamicDataBuilder.GetDataList(e.Result);
       txtUserName.Text = ((User)UserDetails[0]).UserName;

    But it results in typecasting problem.

    Please suggest me a better way to get the details.

    Thanks,

    Rams.

     

     


     

     

     

    Tuesday, July 15, 2008 10:44 AM
  • For the DynamicData List, you can not do something like this:

    ((User)UserDetails[0]).UserName;

    The reason I build DynamicDataList is because I have no pre-defined data object such as the User object. If you have pre-defined data object you can just populate your User List using the DataSet XML data. That would be easier.

    But with DynamicData I have made single row data access possible. It's not in this demo.

    Right now I'm building my List page and Details page using the same list of data. I can build all the pages for our application (for all our objects) without pre-define any object structure. If you are interested, I can mail you some demo.

    Besically I have made the DymanicData a sub class of my DataObject class. The DataObject class has GetFieldValue and SetFieldValue function. that is for accessing each field value.

    public class DataObject : INotifyPropertyChanged
        {       
            public enum DataStates
            {
                Unchanged = 2,
                Added = 4,
                Deleted = 8,
                Modified = 16,
            }
            public DataStates State { get; set; }
            public object GetFieldValue(string fieldname)
            {
                PropertyInfo pi = this.GetType().GetProperty(fieldname);
                if(pi != null)
                    return pi.GetValue(this, null);
                return null;
            }
            public void SetFieldValue(string fieldname, object value, bool initial)
            {
                this.SetFieldValue(fieldname, value);
                if (initial)
                    this.State = DataStates.Unchanged;

            }
            public void SetFieldValue(string fieldname, object value)
            {
                PropertyInfo pi = this.GetType().GetProperty(fieldname);
                if (pi != null)
                {
                    object pValue = Convert.ChangeType(value, pi.PropertyType, null);
                    if (pValue != null)
                        pi.SetValue(this, pValue, null);
                }   
            }
            public void Delete()
            {
                this.State = DataStates.Deleted;
            }
            public void NewRow()
            {
                this.State = DataStates.Added;
            }
            protected void NotifyChange(params string[] properties)
            {
                if (PropertyChanged != null)
                {
                    foreach (string p in properties)
                        PropertyChanged(this, new PropertyChangedEventArgs(p));
                    this.State = DataStates.Modified;
                }
            }
            #region INotifyPropertyChanged Members
            public event PropertyChangedEventHandler PropertyChanged;
            #endregion
        }

     

    The new DynamicDataBuilder code:

    public class DynamicDataBuilder
        {
            private static System.Type BuildDataObjectType(ObservableCollection<GenericService.ColumnInfo> Columns, string DataObjectName)
            {
                AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("AprimoDynamicData"), AssemblyBuilderAccess.Run);
                ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("DataModule");

                TypeBuilder tb = moduleBuilder.DefineType(DataObjectName,
                                                        TypeAttributes.Public |
                                                        TypeAttributes.Class,                                                   
                                                        typeof(DataObject));

                ConstructorBuilder constructor = tb.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);
                foreach (var col in Columns)
                {
                    string propertyName = col.ColumnName.Replace(' ', '_');
                    col.DataType = System.Type.GetType(col.DataTypeName, false, true);
                    if (col.DataType != null)
                    {
                        FieldBuilder fb = tb.DefineField("_" + propertyName, col.DataType, FieldAttributes.Private);
                        PropertyBuilder pb = tb.DefineProperty(propertyName, PropertyAttributes.HasDefault, col.DataType, null);
                        MethodBuilder getMethod = tb.DefineMethod("get_" + propertyName,
                                                                    MethodAttributes.Public |
                                                                    MethodAttributes.HideBySig |
                                                                    MethodAttributes.SpecialName,
                                                                    col.DataType,
                                                                    Type.EmptyTypes);

                        ILGenerator ilgen = getMethod.GetILGenerator();
                        //Emit Get property, return _prop
                        ilgen.Emit(OpCodes.Ldarg_0);
                        ilgen.Emit(OpCodes.Ldfld, fb);
                        ilgen.Emit(OpCodes.Ret);
                        pb.SetGetMethod(getMethod);
                        MethodBuilder setMethod = tb.DefineMethod("set_" + propertyName,
                        MethodAttributes.Public |
                        MethodAttributes.HideBySig |
                        MethodAttributes.SpecialName,
                        null,
                        new Type[] { col.DataType });
                        ilgen = setMethod.GetILGenerator();
                        LocalBuilder localBuilder = ilgen.DeclareLocal(typeof(String[]));
                        //Emit set property, _Prop = value;
                        ilgen.Emit(OpCodes.Ldarg_0);
                        ilgen.Emit(OpCodes.Ldarg_1);
                        ilgen.Emit(OpCodes.Stfld, fb);

                        //Notify Change:
                        Type[] wlParams = new Type[] { typeof(string[]) };
                        MethodInfo notifyMI = typeof(DataObject).GetMethod("NotifyChange",
                        BindingFlags.NonPublic |
                        BindingFlags.Instance,
                        null,
                        CallingConventions.HasThis,
                        wlParams,
                        null);

                        //NotifyChange Property change
                        ilgen.Emit(OpCodes.Ldc_I4_1);
                        ilgen.Emit(OpCodes.Newarr, typeof(String));
                        ilgen.Emit(OpCodes.Stloc_0);
                        ilgen.Emit(OpCodes.Ldloc_0);
                        ilgen.Emit(OpCodes.Ldc_I4_0);
                        ilgen.Emit(OpCodes.Ldstr, propertyName);
                        ilgen.Emit(OpCodes.Stelem_Ref);
                        ilgen.Emit(OpCodes.Ldarg_0);
                        ilgen.Emit(OpCodes.Ldloc_0);
                        ilgen.EmitCall(OpCodes.Call, notifyMI, null); // call nodifyChange function

                        ilgen.Emit(OpCodes.Ret);
                        pb.SetSetMethod(setMethod);
                    }
                }
                System.Type rowType = tb.CreateType();
                //assemblyBuilder.Save("DynamicData.dll");
                return rowType;
            }

            public static IEnumerable GetDataList(GenericService.DataSetData data)
            {
                if (data.Tables.Count() == 0)
                    return null;

                GenericService.DataTableInfo tableInfo = data.Tables[0];

                System.Type dataType = BuildDataObjectType(tableInfo.Columns, "MyDataObject");

                ObservableCollection<DataObject> l = new ObservableCollection<DataObject>();

                var listType = typeof(ObservableCollection<>).MakeGenericType(new[] { dataType });
                var list = Activator.CreateInstance(listType);
               
                XDocument xd = XDocument.Parse(data.DataXML);
                var table = from row in xd.Descendants(tableInfo.TableName)
                            select row.Elements().ToDictionary(r => r.Name, r => r.Value);
               
                foreach (var r in table)
                {
                    var rowData = Activator.CreateInstance(dataType) as DataObject;
                    if (rowData != null)
                    {
                        foreach (GenericService.ColumnInfo col in tableInfo.Columns)
                        {
                            if (r.ContainsKey(col.ColumnName) && col.DataType != null && col.DataType != typeof(System.Byte[]))
                                rowData.SetFieldValue(col.ColumnName, r[col.ColumnName], true);              
                        }
                    }
                    listType.GetMethod("Add").Invoke(list, new[] { rowData });                              
                }
               
                return list as IEnumerable;
            }

            public static string GetUpdatedDataSet(IEnumerable list)
            {
                XElement root = new XElement("DataSet");           
                foreach (DataObject d in list)
                {               
                    if (d.State == DataObject.DataStates.Modified)
                    {
                        XElement row = new XElement("Data", new XAttribute("RowState", d.State.ToString()));                   
                        PropertyInfo[] pis = d.GetType().GetProperties();
                        foreach (PropertyInfo pi in pis)
                            row.Add(new XElement(pi.Name, pi.GetValue(d, null).ToString()));
                        root.Add(row);
                    }
                }
                XDocument xdoc = new XDocument(new XDeclaration("1.0", "utf-8", "yes"), root);
                return xdoc.ToString();                           
            }
        }

    Tuesday, July 15, 2008 11:20 AM
  •  Hi Sladapter,

    Thanks for your reply.

    I am very much interested to see you code. Please give me sample code for inserting and Updating also if you have.

    Here is my email id.

    ramsjone@hotmail.com

    I will be thankful if you send me the code.

    Rams.

    Wednesday, July 16, 2008 8:22 AM
  • Hi Sladapter, I have just posted this question in this thread http://silverlight.net/forums/p/18852/71882.aspx#71882 (in case anybody wants to look), but I am moving it here as you suggested, for the benefit of others I'll post all of the information so far:

    basically I am trying to implement sladapter's solution to displaying a dataset in my datagrid as I need to display dynamic data that I will not always know the exact structure for, therefore this solution is perfect, apart from I am writing it in vb. Now everything appears to be working absolutely fine and I have converted it into vb nicely and I can see the data populating the object that I create within my web service.svc.vb, I'm stepping through it with debug watching it populate, but as soon as it tries to return the result from the service to the silverlight it gets stuck in the transfer and throws up the 404 error. It happens in my Reference.vb in this function:

     

    Public Function EndGetOneRecCRMTable(ByRef CRMTableName As String, ByRef ErrorStr As String, ByVal result As System.IAsyncResult) As Object Implements ServiceReference1.SLService.EndGetOneRecCRMTable

    Dim _args((2) - 1) As Object

    _args(0) = CRMTableName

    _args(1) = ErrorStr

    Dim _result As Object = CType(MyBase.EndInvoke("GetOneRecCRMTable", _args, result),Object)

    CRMTableName = CType(_args(0),String)

    ErrorStr = CType(_args(1),String) Return _result

    End Function

     

    it always highlights the object at the end of this line: Dim _result As Object = CType(MyBase.EndInvoke("GetOneRecCRMTable", _args, result),Object)

    The data I am trying to return is a single record from a sql table made up of fields which include integers and strings, my vb version of your GetData.cs is below, it is not exactly identical as it needs to fit in with the way I have already populated my dataset and also with the way we organise our tableobjects, hopefully I've converted it from c# correctly, thank you again for responding to this:

     

        <OperationContract()> _

    Public Function GetOneRecCRMTable(ByRef CRMTableName As String, ByRef ErrorStr As String)

            Dim CRMTemplateObj As New BusinessLayer.BL_CRMTemplate

            Dim CRMDataSet As New DataSet

            Dim Valid As Boolean = False

            GetOneRecCRMTable = Nothing

     

            Valid = CRMTemplateObj.GetOneRecSLDataSet(CRMTableName, CRMDataSet, ErrorStr)

     

            If Valid Then

                Dim CRMDataSetData As New TableObjects.DynamicDataSetData

                Dim CRMDataTable As New DataTable

     

                CRMDataSetData.Tables = New List(Of TableObjects.DynamicDataTableInfo)

     

                For Each CRMDataTable In CRMDataSet.Tables

                    Dim CRMDataTableInfo = New TableObjects.DynamicDataTableInfo

                    Dim CRMDataColumn As New DataColumn

     

                    CRMDataTableInfo.TableName = CRMDataTable.TableName

                    CRMDataSetData.Tables.Add(CRMDataTableInfo)

                    CRMDataTableInfo.Columns = New List(Of TableObjects.DynamicDataColumnInfo)

     

                    For Each CRMDataColumn In CRMDataTable.Columns

                        Dim CRMDataColumnInfo As New TableObjects.DynamicDataColumnInfo

     

                        CRMDataColumnInfo.ColumnName = CRMDataColumn.ColumnName

                        CRMDataColumnInfo.DataTypeName = CRMDataColumn.DataType.FullName

     

                        CRMDataTableInfo.Columns.Add(CRMDataColumnInfo)

     

                    Next

     

                Next

     

                CRMDataSetData.DataXML = CRMDataSet.GetXml

     

                GetOneRecCRMTable = CRMDataSetData

     

            End If

     

            CRMTemplateObj = Nothing

     

        End Function

    Wednesday, July 16, 2008 12:23 PM
  • I saw your function defination is this:

      Public Function GetOneRecCRMTable(ByRef CRMTableName As String, ByRef ErrorStr As String)

    I don't know if the using ByRef type Parameter works in WCF or not (I have never tried it). You can first test this by taking out "ByRef". I know you might want to return the TableName and error string back. For error string back you can use "Out" parameter ( I know that would work because some one showed code). For table name, you can return the Table name in your DataSetData so you do not need it return as a function parameter.

    Make sure update your service reference after you changed service code. 

     

    Wednesday, July 16, 2008 12:37 PM
  • Hi, the byref definately works on my other functions, it's pretty useful, I'll take it out and try it with this one though, (nice tip with the out parameter) however.....I think I may have found my problem; I'm not serializing properly in my tableobjects. A silly (and embarrassing) mistake of mine, I'm fairly certain it's this that is the problem though! I'll try a couple of things and I'll be back!

    Wednesday, July 16, 2008 12:54 PM
  •  If "byref" works in other functions, then you can keep it. That's not the problem. It's good to know too, I might need it in the future as well.

     If you find serialization problem that most likely is the cause of your 404 error.

    Wednesday, July 16, 2008 12:59 PM
  • Ok if I wasn't bald I'd be tearing my hair out with this now. I think I am serializing my table objects correctly, however where as I notice in the c# version the wcf service seems to be serializing the returned result correctly in reference.cs. However my wcf service does not appear to be serializing my datasetdata at all from looking in reference.vb, in fact from what I can tell it doesn't seem to acknowledge that it needs to be serialized, which seems very strange.

    Does anybody know exactly how to do the serilization in VB? I've tried looking everywhere, but everyones examples all seem to be in c#! Some example code of one of my tableobjects is below, the function remains the same as previously posted.

     

    Imports System.Runtime.Serialization

     

    <DataContract()> Public Class DynamicDataTableInfo

     

        Private mTableName As String

        Private mColumns As List(Of DynamicDataColumnInfo)

     

        <DataMember()> Property TableName() As String

            Get

                Return mTableName

            End Get

            Set(ByVal Value As String)

                mTableName = Value

            End Set

        End Property

     

        <DataMember()> Property Columns() As List(Of DynamicDataColumnInfo)

            Get

                Return mColumns

            End Get

            Set(ByVal Value As List(Of DynamicDataColumnInfo))

                mColumns = Value

            End Set

        End Property

     

    End Class

    Thursday, July 17, 2008 8:50 AM
  • Ha ha! I've solved the passsing over issue, it didn't know what to send it back as and I was not explicitly telling the function. I needed to include this extra part on the end of the first line of the function: as TableObjects.DynamicDataSetData

    Thursday, July 17, 2008 12:43 PM
  • Hi Sladapter,

    I have to save changes made in data grid to the database.

    I have tried to find the modified object in the RowEdited, DataGridColumn_EndEditing events.

    But I am not able find the RowOject because this solution is mainly for generic data display.

    Is there any disadvantages in using LINQ to SQL ?I think we can achieve this easily using LINQ to SQL.

    Could you please suggest me a better way to reflect datagrid changes in database.

    Thanks in advance,

    Rams.

     

    Tuesday, July 22, 2008 8:11 AM
  • Rams,

    I've been busy with something else lately so I have not had time to put up a sample project for you as you asked before. I'll try to do to it today.

    Anyway the only disadvantage for using LINQ to SQL is you need to pre-define object. If your data table is fixed and your list is fixed, your database is Sql server, then using Linq to SQL might be the easiest.

    I can not do it because our data table is not fixed (after we deploy our app, the customer can even change the table to add more columns). Our app need to support both Sql server and Oracle (and other DB). The SQL statement in our application is dynamically build by end user (they use a Filter object and Filter page to define what column they want to see, based on what criteria for each list). In that case, I can not use Linq to SQL because Linq to SQL is still lack those dynamic features. Plus I want to automate the process to generate each list in our application. So for me using generic data list is the best option. 

    But every one has different need. If your case is not like ours then you might be better off to use Linq to SQL. It's very a elegent way to do programming. The code is much easier to understand than the generic way. I like it a lot. If I need to write a simple quick Web application (using Sql server) I definately would choose Linq to SQL.

     

     

     

     

    Tuesday, July 22, 2008 10:10 AM
  • Hi Sladapter,

    Thank you very much for your continuous support.

    You are right. LINQ to SQL lack dynamic feature which is very important for our applications.

    I have tried like this

    • In GetData.cs I have created a function which return list of objects some thing like this.
                  public List<Order> GetOrders(string Sql)
                  {
                      --------------------------
                  }
    • In IGetData interface

                 [OperationContract]
                 List<Order> GetOrders(string SQL);

    When I try to update service reference I am getting the following error.

    The remote server returned an error:(415) Unsupported media type.

    Anyway.... I am waiting for your code.Smile

    Thanks again,

    Rams.

     

     



    Tuesday, July 22, 2008 11:05 AM
  •  Rams,

    The link is updated. You can get the latest now.

    Monday, July 28, 2008 1:09 PM
  • Hi Sladapter,

    Thanks you very much for spending your valuable time for me.

    I will check this and get back to you soon.

    Thanks again.

    Rams.

     

    Monday, July 28, 2008 2:25 PM
  • Thats some sweet code and does an awesome job. I am running into a weird issue though. My column info is getting repeated on every row.

    This is what i mean:

     Col1 Col2 Col3 Col1 Col2 Col3 State

    where Colx is a column in a row. Also, it adds a State Column at the end. When i debug the code, the columns collection does not contain repeated values and it does not contain the "State" column either.

    Any help would be appreciated.

     

    Thanks,

    Thursday, February 26, 2009 3:33 PM
  • Make sure AutoGenerateColumns="False" on your DataGrid. The "State" Column is a Property for every DataObject to indicate any DataChange for that row. When you build you DataGrid.Columns collection, you should check to skip this column because you do not want to display it. I'll update my demo when I have time. 

    The code I provided only meant to show people how to do things this way. It is not the code you can just use without any modification. If you want to go this way, you need to understand the code. Then you can make it work for your case.


     

    Thursday, February 26, 2009 3:59 PM
  • Hello Sladapter,

    I am trying to use your code for the datagrid in my Porject as our requirement is very much similiar to get the data Runtime. I wrote a Store Procedure to get the data, here is what I get:

    Description                    Stage 1 To Stage 2             Stage 2 To Stage 3               Stage 3 To Stage 4

    ----------------------------------------------------------------------------------------------------------------------------------------

    Untreated                           100.00                                     60.00                                40.00
    Quarters                               5.00                                      3.00                                  2.00
    Deaths                                 100.00                                 50.00                                 20.00
    Quarters                                 3.00                                   1.50                                   0.60
    Cures                                 100.00                                    50.00                                 50.00
    Quarters                                 4.00                                   2.00                                   2.00

     What we want is to do calculations on the editable cells. Here 1st, 3rd and 5th rows 3th and 4th cell is editable. Whenever user changes 60 to anything then the calculation will be as follows:

    consider A[0][0] as Untreated cell and likewise others.

    so A[1][2] = A[1][1] * (A[0][2] / 100)

    A[1][3] = A[1][1] * (A[0][3] / 100 )

    but when I edit A[0][2] it updates the dataset but doesnt do the calculation. I hope I made myself clear.

    Can you please help me.

    Thnanks in advance.

    Friday, March 06, 2009 3:27 AM
  •  varshavmane,

    I'm not sure I understand you. Where did put your logic to do the calculation? Do you have code in Silverlight to do the calculation based on user input and update your data that bind to the DataGrid?

    Friday, March 06, 2009 9:04 AM
  • Thanks for the reply. Actually I am trying to put the logic in LostFocus Event of Datagrid but the problem is that I dont get the next row index. I have to do the calculation on the edit cel and the next row of that editable row.

    Can you please tell me how to do this as I dont want to go to WCF Service to do the calculations.

    Also once I finish with everything I have to save all the values to database on save button click event.

    Thanks again.

    Friday, March 06, 2009 9:41 AM
  • If this has any appeal to you -- please vote for a DataTable / DataSet feature to be added to the Silverlght toolkit:

    DataTable and DataSet support - http://silverlight.codeplex.com/WorkItem/View.aspx?WorkItemId=2810

    Tuesday, April 21, 2009 4:25 PM
  • Hi sladapter,

    I downloaded the source code of the given URL. But It was coded in C#.

    I tried to convert this code to VB.NET resulting so many syntax errors.  ( I am using Silverlight 3.0 beta)

    Is there any option for me to download this same project in VB.NET.

    Thanks in Advance...

    Wednesday, April 22, 2009 7:04 AM
  • Sorry, I don't have the project in VB.NET. But I'm not sure converting it to VB.NET should be that hard. I used to use VB before C# came out, so I don't think the syntax difference between VB and C# are that significant.  

    I haven't tried the project in SL3 beta yet.

    Wednesday, April 22, 2009 9:06 AM
  • Hi,

    I converted the entire solution into VB.NET.  I'm facing unsolvable issues in few places.

    1.  DynamicDataBuilder.VB has error in following lines.

    Dim listType = GetType(ObservableCollection(Of )).MakeGenericType(New() {dataType})

    listType.GetMethod("Add").Invoke(List,new() {rowData})

    Also.  In the WCF service i imported system.data.common and used "DBParameter" as one of the parameter to the OperationContract.  This gives error in Reference.VB.  This applies to generic "DBTransaction" too.  Below is the error causing line.

     <System.Diagnostics.DebuggerStepThroughAttribute(), _
         System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0"), _
         System.Runtime.Serialization.DataContractAttribute(Name:="DbParameter", [Namespace]:="http://schemas.datacontract.org/2004/07/System.Data.Common"), _
         System.Runtime.Serialization.KnownTypeAttribute(GetType(System.MarshalByRefObject)), _
         System.Runtime.Serialization.KnownTypeAttribute(GetType(OPaLDataService.DBFrameworkExecuteMethod)), _
         System.Runtime.Serialization.KnownTypeAttribute(GetType(System.Collections.ObjectModel.ObservableCollection(Of OPaLDataService.DbParameter))), _
         System.Runtime.Serialization.KnownTypeAttribute(GetType(OPaLDataService.DbTransaction)), _
         System.Runtime.Serialization.KnownTypeAttribute(GetType(OPaLDataService.CustomException)), _
         System.Runtime.Serialization.KnownTypeAttribute(GetType(OPaLDataService.DataSetData)), _
         System.Runtime.Serialization.KnownTypeAttribute(GetType(System.Collections.ObjectModel.ObservableCollection(Of OPaLDataService.DataTableInfo))), _
         System.Runtime.Serialization.KnownTypeAttribute(GetType(OPaLDataService.DataTableInfo)), _
         System.Runtime.Serialization.KnownTypeAttribute(GetType(System.Collections.ObjectModel.ObservableCollection(Of OPaLDataService.DataColumnInfo))), _
         System.Runtime.Serialization.KnownTypeAttribute(GetType(OPaLDataService.DataColumnInfo)), _
         System.Runtime.Serialization.KnownTypeAttribute(GetType(OPaLDataService.DbType)), _
         System.Runtime.Serialization.KnownTypeAttribute(GetType(OPaLDataService.ParameterDirection)), _
         System.Runtime.Serialization.KnownTypeAttribute(GetType(OPaLDataService.DataRowVersion)), _
         System.Runtime.Serialization.KnownTypeAttribute(GetType(OPaLDataService.CommandType))> _
        Partial Public Class DbParameter
            Inherits System.MarshalByRefObject
            Implements System.ComponentModel.INotifyPropertyChanged

     

    Any help will be appreciated.

    Regards

    RV

    Thursday, April 30, 2009 3:28 AM
  • Hi,

    I read lot of articles regarding Returning dataset result to Silverlight to fill Grid control.

    None matched with my requirement.

    Procedure i am following to Bind the Grid: 

    Step 1) I am requesting to WCF to bind grid.

    Step 2) wcf is going to class file called as controller.vb

    Step 3) controller is requesting to BuildQuery class file

    Step 4) BuildQuery.vb file requesting to ExecQuery.vb file.

    Step 5) In this class file (ExecQuery.vb) , query is executing against the DataBase, and result is storing in DATASET.

    As i know, we can't pass DATASET directly from WCF to bind the grid.

    So, i need to perform some manipulations here and the result is passed through WCF to bind my Grid.

    Whats the mechanism i need to follow here.

    REQUIREMENT is no class files should be added in Silverlight application.

    Can any one please help me on this..

    Monday, June 01, 2009 6:14 AM
  •  this is a really nice piece of programming skills

     

    thanks for this sladapter!

    Monday, June 01, 2009 6:48 AM
  • HI sladapter,

    I worked on your link and it's working fine.

    If suppose i don't to perform any operations at client side, [as you did sending data to dynamicbuilder class etc],

    Every thing should be done at service and the resultSet should be bind to grid directly.

    Is there any approach for this.

    OR  Shall i get the data from WCF method( in the form of DataSetData and doing any manipulations at SL xaml page)

    (I did the following work, it worked only for columns, but data is not binding)

    AT WCF Side:

    <OperationContract()> _
        Public Function ReceiveFromSL(ByVal sAppFlow As String, ByVal sStepName As String) As DataSetData
            Dim oController As XICore.XIController
            oController = New XICore.XIController()
            Dim strr12 As String = ""
            Return oController.StepExecute(sAppFlow, sStepName)
        End Function
     At xaml side  

    MessageBox.Show(e.Result.DataXML())   --> displaying total result in the form of xml (columns  +   Data)

    For Each mylval In e.Result.Tables()

    For Each col In mylval.Columns

    Dim TextColumn As New DataGridTextColumn

    TextColumn.Header = col.ColumnTitle

    TextColumn.Binding = New Binding("kumar")

    GrdCollection.Columns.Add(TextColumn)    --> only column is binding, but not data

    Next

    Next

     How can i bind Column followed by data to my GRID

    Thanks in Advance....

    Friday, June 05, 2009 2:50 AM
  •  

     Sir,

    i  have started using silverlight before few days.This post  related to Display DataSet in Silverlight DataGrid was as per my requirement as i do not want to create class and its object while binding data to silverlight datagrid I downloaded this code and when i was debugging to understand its flow, i found out that i am getting exception of type System.NotSupportedException  in DynamicDataBulider.cs and a result after execution of very first line  i.e.         AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("AprimoDynamicData"), AssemblyBuilderAccess.Run); in BuildDataObjectType() function.I guessed that it has something to do with assembly AprimoDynamicData which i do not find in application.And as a result of all these things,i am not getting data to bind it to my grid.So can u plz help me out in solving this issue.

    Thanks and Kind Regards,

    Rushi Patel.

    Saturday, June 13, 2009 7:47 AM
  • i don't think so you will get any problem while running the application as it is.

    Might you need to change database connections. try deleting and adding reference once again.

    let me know still any problems

    Monday, June 15, 2009 7:19 AM
  •  Hi,

    As you have mentioned that i need to give reference to dll.But i did not find concerned dll with the code i have downloaded.I have also make sure that i have connection with my local database.Error which i was facing before still persists.

    Thanks and Kind Regards,

    Rushi.

     

     

    Friday, June 26, 2009 1:05 AM
  • "AprimoDynamicData" is the name I gave to the Dynamic Assembly I was trying to build. That assembly is dynamically built when you run the code trying to build the dynamic data object. You can not add reference of this dll in your project because it's dynamically built. You can change  "AprimoDynamicData" to any name you want.

    The solution file should already have everything you need to run this demo. The only thing you need to do is to change the connection string in the GetData.cs under the DataSetInDataGrid.Silverlight_Web/App_Code folder to a connection string to connect to your SQL server database, then build your solution.

    public class GetData
    {
        // Change this connection string to your need.
        private const string connectionString = @"Data Source=LOCALHOST;Initial Catalog=Northwind;Integrated Security=True;";
       

    ...

    }

     

    Are you sure you are getting error on the following line?

    AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("AprimoDynamicData"), AssemblyBuilderAccess.Run);

     

     

     

    Friday, June 26, 2009 10:04 AM
  • Thanks sladapter,

    It works perfectly this time. 

    Thanks and Regards,

    Rushi Patel.

     

    Monday, June 29, 2009 1:49 AM
  •  I know its a silly thing to ask, but can u please tell me the steps to create this program ..

     

    Tuesday, July 21, 2009 12:47 AM
  •  I listed all the steps on my first post.

    Tuesday, July 21, 2009 9:23 PM
  •  My problem is that i have to create a custom datagrid control with a dynamic wcf service. The linq class will be in the client application. So how should i know the return type of my wcf service when i don't know the table the user wants the data from .

    Please help .. 

    Wednesday, July 22, 2009 5:27 AM
  • I still don't quite understand your problem. But sounds like you do not need this displaying DataSet in DataGrid approach. There are many ways to display DB data in a DataGrid. Such as Linq to SQL + WCF service, ADO DataService,  the new .NET RIA Services in SL3 etc. You might want to read more about them.

     

    Wednesday, July 22, 2009 1:38 PM
  • Hi guys,

    There is a way to bind ADO.Net DataSet to Silverlight DataGrid or any other controls.

    Here is a solution: http://silverlightdataset.codeplex.com/

    You can ping me for additional information at vlaskarzhevsky@msn.com

    Enjoy your coding.

    Vitaly Laskarzhevsky

    Wednesday, July 22, 2009 10:06 PM
  •  Vitaly,

    Thanks for the link and solution. I downloaded your code and tried it. Nice stuff! Glad more people are working on this direction. Because DataSet support is definitely needed.

    One problem I found with your demo is that if I set DataGrid.AutoGeneratedColumn to true, then no real data is displayed. Same problem with the SL3 DataForm.  Have you noteced?

     


     

    Wednesday, July 29, 2009 11:04 PM
  • Read all the posts to date, read the linked articles and tried some of the samples.  I'm impressed, I should have checked here a long time ago.

    Here's what I'm looking for. I already have a large investment in server(and client) processing of non-typed datasets. Both our web and winform clients use the results.  It would be nice to have a CSharp class for Silverlight that takes in an dataset xml, changes it into a strong typed object for multple data binding: data grid and data form... and then finally, allows me to return a dataset diffgram xml to the server for optimistic(optional) updating.

    Besides the actual objects for data binding in Silverlight, it should also allow indexed access should we need to get at the table and fields from code.  Maybe something like the following code:

    DataSet ds= ParseData(DataSetXml).ToDataSet();
    this.theGrid.ItemsSource = ds["Table1"]; //bind to strong typed table
    

    Anyone interested?

    Tuesday, August 11, 2009 1:23 AM
  • Didn't you see VitalyL's code? That's similar to what you want, having Silverlight DataSet (restored from the DataSet XML string) mimic the ADO.DataSet.

    The only thing I found in that code is that it does not quite work with autogenerate columns. Seems I have to pre-define each column for DataGrid or DataForm which I'd prefer not to do. That's kind of missing the benefit of using the generic feature of a DataSet. Maybe VitalyL already figured out the problem and solved it.

    With the new tagging method provided by SL3 System.ComponentModel.DataAnnotations namespace and DataForm, I found more benifit of using DataSet. A DataSet not only holds the data, it can also holds the data schema which contains the meta data for each field.  Now my code can convert a DataSet to a Dynamic Data structure with all the necessary meta data tags on each Data Field being added. So I can just bind them to a DataGrid or a DataForm without any extral code or XAML setup. 

    If a data field can not be null in the database, it will be a required field in the DataForm. If a data field is a string in database with certain length limit, it will has the same length limit in the DataForm textbox. If a data field is an identity field in database which is autogenerated,  it will be a read only field in DataForm and DataGrid. Most of the validations are build-in without any extral code. When data is changed in Silverlight, only the changed data is sent back to Server for updating.

     

     

     

     

     

     

    Tuesday, August 11, 2009 10:40 AM
  • Yes, I did say I saw the samples.  It still requires work to make it a true diffgram xml.

    What you say it lacks... I agree with.

    Have you tried ComponentOne's DataTable, etc.? Does it come close to MS DataSet?

     

    Tuesday, August 11, 2009 8:59 PM
  •  No, I have never tried ComponentOne's DataTable.

    Wednesday, August 12, 2009 9:17 AM
  • Hi sladapter

    I've downloaded the code that VitalyL has provided. But I'am not able to get that working.

    I created my project and tried to like this:

     

    SqlConnection con = new SqlConnection("Data Source=.;Initial Catalog=svlsample;Integrated Security=True");

    SqlCommand cmd = new SqlCommand();

    cmd.CommandText = "SELECT * FROM " + table_name;

    DataSet ds = new DataSet();

    // DataTable dt = new DataTable("TableRecords");

    SqlDataAdapter da = new SqlDataAdapter(cmd);

     

    cmd.Connection = con;

    con.Open();

    da.Fill(ds);

    con.Close();

    The code work fine untill here. However when adding 2 code line below it will not work

    string response = (string) Connector.ToXml(ds);

    return response;

    When am trying to debug without the last 2 lines of code, everything ok... but when i add them and while debugging i can't enter the service method and this exception occured:

    public string EndGetMyDataSet(System.IAsyncResult result) {                object[] _args = new object[0];                string _result = ((string)(base.EndInvoke("GetMyDataSet", _args, result)));                return _result;            }

    Error: The remote server returned an error: Not Found

    Can you guide me plz?

    I hope am clear... !!!

    Monday, August 17, 2009 11:45 AM
  • Hi sladapter

    I've downloaded the code that VitalyL has provided. But I'am not able to get that working.



    I'm not  VitalyL, maybe you asked wrong person?

     

     

    Monday, August 17, 2009 12:23 PM
  • Hi,

    Sorry, I've asked u because I read that u have downloaded the code and tested it. And you are right I must ask Vitalyl.

    Hi VitalyL, please can u guide me what am doing wrong ?

     

    Monday, August 17, 2009 1:01 PM
  • No problem.

    I read your post again, do you mean the error happens at the following line? Didn't you debug the code to see what happens there? Do you even got the DataSet?

    string response = (string) Connector.ToXml(ds); 

    I have no problem running the sample code. The only problem I found is to auto bind the data to control as I mentioned in earlier post.

     

    Monday, August 17, 2009 8:02 PM
  • Hi,

    Thanks sladapter,

    Plz let me tell what i had since i downloaded the demo sample. Am using VS 08 professional edition , Windows Vista Tongue Tied, , IIS 7

    First when i opened the project i got a warninig message told that i dont have IIS6 metabase and configuration I've downloaded them, then

    when am opening the project in normal user ( it show warning msg i need windows authentication :S) and i found that the website is not accessible. Until i run as administrator.And also when am runniing i also see the default page then nothing....

    So, I decided to open new SL project which contains web app, to get rid of this headache. The SL app contains the service method (GetMyDataSet) i put in the previous post.

    So when I debugg the mothod without the code line below, the debugger enters to the method and everything works fine.

    string response = (string) Connector.ToXml(ds); 

    However, when i add this method, the debugger will not access the mothod at all, and i will get the exception in this method in this line.

    public string EndGetMyDataSet(System.IAsyncResult result) {                object[] _args = new object[0];                string _result = ((string)(base.EndInvoke("GetMyDataSet", _args, result)));                return _result;            }Error:

    The remote server returned an error: Not Found.

    And really thank u in advance.

     

    Tuesday, August 18, 2009 3:33 AM
  • However, when i add this method, the debugger will not access the mothod at all

     

    You mean you could not catch the break point you set on the WCF GetMyDataSet function at all when you added one line of code there?

    Try to update your Service Reference first, rebuild the solution then try it again.

    Tuesday, August 18, 2009 10:43 AM
  • Hi guys,

    Silverlight DataSet supports DataGrid with AutoGenerateColumns="True" now.

    You can download the latest libraries from http://silverlightdataset.codeplex.com

    Enjoy your coding

    Vitaly

    Friday, August 21, 2009 10:39 AM
  •  Silverlight DataSet project was moved to http://silverlightdataset.net

    Friday, August 28, 2009 9:50 AM
  • If you check out www.silverlightDS.com they have a download which makes doing SQL alot easier, simplifies the whole process, just need to define the CrUD in the webservice, and then wala!  It's pretty slick.

    Sunday, October 04, 2009 4:12 PM
  • Where to download source code of silverlightdataset.net ?

    There is no source download link.

    Andrus.

    Sunday, October 11, 2009 9:33 AM
  • Check this:

    http://slbindabledatagrid.codeplex.com/

    Hope it helps.

    Monday, October 12, 2009 1:54 AM
  • http://slbindabledatagrid.codeplex.com/ has GPL licence. So unfortunately I cannot use it.

    Andrus.

    Monday, October 12, 2009 4:49 AM
  • Hi there,

    Source code is located at http://silverlightdataset.net

    Scroll treeview down untill you see "Source Code" node.

    Best regards

    Vitaly

    Monday, October 12, 2009 9:03 AM
  • Where to downlaod whole solution as zip file ?

    Andrus.

    Monday, October 12, 2009 9:09 AM
  • Hi Andrus,

    There is no such an ability. Contact me directly at vlaskarzhevsky@msn.com for futhure discussion, please.

    Regards

    Vitaly

    Monday, October 12, 2009 9:18 AM
  • Hi Andrus,

    There is no such an ability. Contact me directly at vlaskarzhevsky@msn.com for futhure discussion, please.

    Regards

    Vitaly


    You removed the project from Codeplex, are you taking it commercial?
    Monday, October 12, 2009 2:52 PM
  • Is there a way to dispose and reclaim the memory taken by this dynamically generated assembly and type? I tried your sample and it works great. But I could see memory leaking at the TypeBuilder.CreateType line. After binding to the grid, how can we dispose this type?

    Wednesday, October 14, 2009 7:16 AM
  • Hi Sangasan,

    It is not a memory leak. According to Miocrosoft, loaded assembly (doesn't matter generated or created at design time) cannot be unloaded from memory until application shutdown. You just need to be aware of this effect when you design any of your application.

    Regards

    Vitaly

    Wednesday, October 14, 2009 8:33 AM
  • Hi Vitaly,

    I downloaded your stuff ... looks promising, but I haven't had a chance to really look at it yet. I'm curious though, as to why you removed it from CodePlex? It seems to me that you might get a lot of exposure by having it there ... or is that not the case?

    ... just curious.  Thanks.

    ~~Bonnie

     

     

    Saturday, October 31, 2009 12:21 PM
  • Hi Bonnie,

    Unfortunately CodePlex doesn't provide the level of freedom we need in posting documentation for Silverlight DataSet a la MSDN Reference. That was the first obstacle. Te second dissapointment was the unability to upload information using simple FTP and Windows Explorer.

    That's why we chose DiscountAsp as a host for our project.

    Sincerely

    Vitaly Laskarzhevsky

    Saturday, October 31, 2009 8:45 PM
  • Thanks Vitaly.

    Another question ... I assumed (wrongly apparently), that we could also download the source code, but apparently you're only giving access to the DLL? Any chance of getting the source code from you guys?

     UPDATE: Oh, I see you include the source code on your website, but not as a download. It looks like I'd have to copy/paste every single class. But, if that's what I have to do, I guess I can manage.

    Thanks!

    ~~Bonnie

    Sunday, November 01, 2009 5:45 PM
  • Hi Bonnie,

    Source code was published only for public classes on our website. We see no business value in publishing internal and private classes.

    Best Regards

    Vitaly Laskarzhevsky

    Sunday, November 01, 2009 8:03 PM
  • Hi Vitaly,

    I will email you via your website with further questions.

    ~~Bonnie

    Sunday, November 01, 2009 8:33 PM
  • Hi Sladapter,

    I got some kind of hope after i saw your article.My problem was the same how you are having.But in our application we are using RIA services.Can i implement your code with RIA services as well.I am getting data reader from Database i can convert that to XML but i have no idea weather i can retunr it from RIA services

     

    Thanks

    Saritha 

     

    Monday, April 26, 2010 5:35 PM
  • I got some kind of hope after i saw your article.My problem was the same how you are having.But in our application we are using RIA services.Can i implement your code with RIA services as well.I am getting data reader from Database i can convert that to XML but i have no idea weather i can retunr it from RIA services

     

    Are you using Entity Framework with RIA service? Because RIA service works best with Entity Framework.

    If yes, I don't know why you want to use my solution. You only need my solution when you can not have pre-defined entity or data object.

    When you do not have pre-defined data object, you lost the benefit of using RIA service. So I don't see the point of using RIA service. But if you use RIA service as a regular WCF service, write your own functions as Invoke functions. Then I don't see why you can not use it, because RIA service is still a WCF service. 

     

     

    Monday, April 26, 2010 5:55 PM
  • Hi Good to see your reply,

    In my case also i do not have predefined entity object.But we are using RIA services with entity frame work since i have to use the RIA services and only possible solution i could see from reply is invoke functions.

    Could you please explain me bit about  your solution how can i use uisng RIA services with INvoke funcitons.

    That will be great help me since i am new to RIA services.

    Thanks In Advance

    Saritha 

     

    Tuesday, April 27, 2010 10:54 AM
  • I'm still puzzled by your question. If you use Entity Framework with RIA, why do you still need my solution? 

    As I said, you only need my solution when you can not pre-define Data object or Entity. With Entity Framework, every entity is already pre-defined. I don't understand why you still need dynamic generated object.

    Tuesday, April 27, 2010 11:04 AM
  • sladapter, in using your posted datasetindatagrid solution, have you come up with an elegant way to do hyperlinks dynamically? It would seem the URL must come from the database to be truly dynamic.  However, in fetching them from the database, there must be some mechanism to signal which data column the URL belongs to. This could be accomplished by naming the URL in such a way that its matching data column can be determined, but all this seems like a hack. Have you had need to solve this problem?

    Tuesday, April 27, 2010 11:09 AM
  • I will try explain my Problem.

     

    in our solution we are using RIA service with entity framework

    I have a search control and Query will generate dynamically.Query may contains data from different tables.Until it run i dont know what it will return(What columns it will return).

    That is the reason i ma trying to use your solution.

    Thanks

    Saritha 

     

    Tuesday, April 27, 2010 11:17 AM
  • I am waiting for your reply Sad

     

    Thanks In Adavnce

    Saritha

    Tuesday, April 27, 2010 11:20 AM
  • sladapter, in using your posted datasetindatagrid solution, have you come up with an elegant way to do hyperlinks dynamically? It would seem the URL must come from the database to be truly dynamic.  However, in fetching them from the database, there must be some mechanism to signal which data column the URL belongs to. This could be accomplished by naming the URL in such a way that its matching data column can be determined, but all this seems like a hack. Have you had need to solve this problem?

     

    You need to extend DataColumnInfo class to put more info for each column to fit your need. DataColumnInfo basically serves as metadata for each column. So if you need a Hyperlink column, you need to have all the information (such as where the display Content come from, URL format string, etc) in the DataColumnInfo to describe what you need. Then you can build the column based on those information.

    In my demo, I only used Field info from DataSet schema to build the ColumnInfo, But in real world, your column info might come from a metadata table or XML file for each object, so you need to build your ColumnInfo yourself. Then write code to build the UI control based on those info.


     

     

    Tuesday, April 27, 2010 11:47 AM
  • in our solution we are using RIA service with entity framework

    I have a search control and Query will generate dynamically.Query may contains data from different tables.Until it run i dont know what it will return(What columns it will return).

     

    OK, in that case I need to try it myself first before I can tell you how to do it.

    Tuesday, April 27, 2010 11:51 AM
  • Excellent, using metadata tables and extending the DataColumnInfo class is the route I was contemplating.  Thanks for the confirmation. I guess tighter coupling between the DataColumnInfo class and the metadata tables is acceptable.

    Of course, thanks again for your help!

    Tuesday, April 27, 2010 11:54 AM
  • Hi,

    Just for reference, I have an alternative solution which I posted to my blog:

    http://www.scottlogic.co.uk/blog/colin/2010/03/binding-a-silverlight-3-datagrid-to-dynamic-data-via-idictionary-updated/

    See the example about half way down the article where dynamic data in XML is 'bound' to the DataGrid, you can also go the other way, from the data in the DataGrid to XML.

    Regards,

    Colin E.

    Tuesday, April 27, 2010 12:07 PM
  • Hi,

    I am trying to use this technique to get data using SQL dynamic query in my WCF RIA Services DOmain Services ( with LINQ to Entities)

    How to bind Silverlight DataGrid from IEnumerable of IDictionary by transforming each dictionary key into property of anonymous typed object

    And trying to fill the Dictionary<string ,object> with my table's column and values. My Server (Web) project is compliling fine but on Clinet(Silverlight) I am getting this error Error "Type 'IDictionary' is not a valid entity type.  Entity types cannot be a collection type. SL"

    I have tried to create my custom class on server side wich has property Dictionary<string ,object> , and retur this class object as return type, but still get an error on SIlverlight Client side.

    Have any one tried this approach using WCF RIA Services ?

    Thanks for your help.

    Sunny

    Thursday, April 29, 2010 6:22 AM
  • Hello Sladapter,

    I think Singamaneni & I share same problem, I am also using RIA services with EF and dont have entity defined at design time to return. So plz guide us to how to resolve this issue in RIA services .

    Thanks for your valuable time.

    Sunny

    Thursday, April 29, 2010 8:29 AM
  • I'm pretty busy with my current project right now. I'll get back to this and post code on how to combine RIA service with my dynamic data solution later. Currently I'm halfway through it, and have already proved it definitely would work with RIA service.

    By the way, you can not pass Dictionary<string,object> with RIA service. RIA service does not currently support Dictionary.  It support List or Collection.


     

     

     

    Thursday, April 29, 2010 9:53 AM
  • Hi sladapter

    I am trying to implement your solution using RIA services.When i sending datasetdata from Domain service i am able to pass only XML string i am not able to pass tables and Column info.I am not getting why i am unable send it.If you think i am missing any thing please guide me.Here is the code for Class declaration

    [Serializable()]
        public class DataSetData
        {

            [Include]
            [Association("ListTables", "TableName", "TableName")]
            [DataMember]
            public Collection<DataTableInfo> Tables { get; set; }
            [Key]
            [DataMember]
            public string DataXML { get; set; }
            [Key]
            [DataMember]
            private string tableName ;
            public string TableName
            {
                get
                {
                    return tableName;
                }
                set
                {
                    tableName = value;
               
                }
            }

            public static DataSetData FromDataSet(DataSet ds)
            {

               
                DataSetData dsd = new DataSetData();
                dsd.Tables = new   Collection <DataTableInfo>();
                foreach (DataTable t in ds.Tables)
                {
                    DataTableInfo tableInfo = new DataTableInfo { TableName = t.TableName };
                    dsd.Tables.Add(tableInfo);
                    dsd.TableName = t.TableName;
                    tableInfo.Columns = new Collection<DataColumnInfo>();
                    foreach (DataColumn c in t.Columns)
                    {
                        DataColumnInfo col = new DataColumnInfo { ColumnName = c.ColumnName, ColumnTitle = c.ColumnName, DataTypeName = c.DataType.FullName, MaxLength = c.MaxLength, IsKey = c.Unique, IsReadOnly = (c.Unique || c.ReadOnly), IsRequired = !c.AllowDBNull };
                        if (c.DataType == typeof(System.Guid))
                        {
                            col.IsReadOnly = true;
                            col.DisplayIndex = -1;
                        }
                        tableInfo.Columns.Add(col);
                    }
                }
                dsd.DataXML = ds.GetXml();
                return dsd;
            }
        }

        [Serializable()]
        public class DataTableInfo
        {
            [Key]
            [DataMember]
            public string TableName { get; set; }
           
          
            [DataMember]
            private string columnName = "Coulmn";
            public string ColumnName
            {
                get
                {
                    return columnName;
                }
                set
                {
                    columnName = "Coulmn";

                }
            }

            [Include]
            [Association("ListColumns", "ColumnName", "ColumnName")]
            [DataMember]
            public Collection<DataColumnInfo> Columns { get; set; }

        }

        [Serializable()]
        public class DataColumnInfo
        {
            [Key]
            [DataMember]
            public string ColumnName { get; set; }

            [DataMember]
            public string ColumnTitle { get; set; }

            [DataMember]
            public string DataTypeName { get; set; }

            [DataMember]
            public bool IsRequired { get; set; }

            [DataMember]
            public bool IsKey { get; set; }

            [DataMember]
            public bool IsReadOnly { get; set; }

            [DataMember]
            public int DisplayIndex { get; set; }

            [DataMember]
            public string EditControlType { get; set; }

            [DataMember]
            public int MaxLength { get; set; }
        }

     Since i am new to RIA services i am uisng trail and error to get my solution

     

    Thanks

    Saritha

    Thursday, April 29, 2010 10:58 AM
  • You are on the right path:

    Every class need to be Tagged with [DataContract]

    Every class need to have a Field tagged with [Key], and this field need to be populated.

    Child collection need to be Tagged with [Association] and [Include] tag.

    With those things set, you should be able to pass everything in DataSetData to Silverlight with a Query function.

    Write a RIA service Query function:

    public DataSetData GetDataSetData( string SQL, int PageNumber, int PageSize)
            {
                //Return your DataSetData;           
            }

    If you only need to display data without updating, this is all you need to do.

    If you also need to do Update:

    You need to write 

      public void UpdateDataSetData(DataSetData d)
            {
                //Your Update(Insert/Delete/Update) code here               
            }

            public void InsertDataSetData(DataSetData d)
            {         

                //leave it empty 
            }

            public void DeleteDataSetData(DataSetData d)
            {         

                 //leave it emtpy
             }      

    If you need to pass the DataSetData (with all the child collection) back to server to do update, make sure you Tag the DataTableInfo and  DataColumnInfo collection with [Composition] tag.

     

     

     

     

     

     

     

    Thursday, April 29, 2010 12:15 PM
  • Hi,

    To give [Association] for child colelction we need to have common column between datasetdata and datatable info.So i added one proeprty for table name to Assoicate  datasetdata and datatableinfo.

     

    Even thought i am not getting child colelction from client side.When i am executing query it is returing proeprly when i ma trying to access the object i am only getting XML string Sad. Please guide me

     

     

    Thanks

    Saritha

    Thursday, April 29, 2010 2:11 PM
  •  Oh, I know what you are missing. You added a Association Tag, but you did not add the Field for the association.

    DataSetData should  have a Name Field, Add DataSetName Field in DataTableInfo class. The association should link DataSetData.Name to DataTableInfo.DataSetName,

    Add TableName field to the DataColumnInfo class, the assocication should link DataTableInfo.TableName  to DataColumnInfo.TableName.

     [DataContract]
        public class DataSetData
        {
            [DataMember]
            [Key]        
            public string DataSetName { get; set; }
            
            [DataMember]
            [Include]
            [Association("DataSetData_DataTableInfo", "DataSetName", "DataSetName")]
            //[Composition] optional, only needed if you need to pass DataSetData back
            public List<DataTableInfo> Tables {get;set;}

            ...

       }

    [DataContract]
        public class DataTableInfo
        {
            [DataMember]
            [Key]        
            public string TableName { get; set; }

            [DataMember]
            public string DataSetName { get; set; }
                      
            [DataMember]
            [Include]
            [Association("DataTableInfo_DataColumnInfo", "TableName", "TableName")]     
            public List<DataColumnInfo> Columns {get;set;}

            ...

       }

     [DataContract]
        public class DataColumnInfo
        {

            [DataMember]
            [Key]        
            public string ColumnName { get; set; }       

            [DataMember]
            public string TableName { get; set; }

            ...

      }

    Thursday, April 29, 2010 2:20 PM
  •  Thank you so much for your reply.Really you saved me.I am getting data.

     

    I have onde doubt

    DynamicDataBuilder.GetDataList(data);

    I am unable to see the data what it returns. But when i am  debugging the function i am able to see the data operations.

     

    But any way Thank you so much for your help and time.

     

    Thanks

    Saritha

    Thursday, April 29, 2010 4:47 PM
  •  Hi Sladapter,

     

    You been a great help for me.With your help i could make it work.Thanks from bottom of my heart.

     

    Thanks

    Saritha

    Thursday, April 29, 2010 6:10 PM
  • Hi Singamanen,

    Can you please share source code of your RIA Services working solution  . It will be great help to many who are trying to implement Sladapter solution using RIA Services.

    Thanks,

    Sunny

    Friday, April 30, 2010 2:13 AM
  • Hi Saritha,

    did u manage to compile the final source code ?

    Can you plz share it with us ?

    Thanks.

    Friday, April 30, 2010 1:47 PM
  •  Hi Sunny,

     

     Sorry for the late reply.I will share the code how i developed using RIA services.

    These are 3 main Classes which needs to be in BUsinessObjects:

     

    [Serializable()]
        [DataContract]
        public class DataSetData
        {

            [Include]
            [Association("ListTables", "DataSetName", "DataSetName")]
            [DataMember]
            public Collection<DataTableInfo> Tables { get; set; }
            [Key]
            [DataMember]
            public string DataXML { get; set; }

            [DataMember]
            public string DataSetName { get; set; }

            public static DataSetData FromDataSet(DataSet ds)
            {

               
                DataSetData dsd = new DataSetData();
                dsd.Tables = new   Collection <DataTableInfo>();
                foreach (DataTable t in ds.Tables)
                {
                    DataTableInfo tableInfo = new DataTableInfo { TableName = t.TableName };
                    dsd.Tables.Add(tableInfo);
                    tableInfo.Columns = new Collection<DataColumnInfo>();
                    foreach (DataColumn c in t.Columns)
                    {
                        DataColumnInfo col = new DataColumnInfo { ColumnName = c.ColumnName, ColumnTitle = c.ColumnName, DataTypeName = c.DataType.FullName, MaxLength = c.MaxLength, IsKey = c.Unique, IsReadOnly = (c.Unique || c.ReadOnly), IsRequired = !c.AllowDBNull };
                        if (c.DataType == typeof(System.Guid))
                        {
                            col.IsReadOnly = true;
                            col.DisplayIndex = -1;
                        }
                        tableInfo.Columns.Add(col);
                    }
                }
                dsd.DataXML = ds.GetXml();
                return dsd;
            }
        }

        [Serializable()]
        [DataContract]
        public class DataTableInfo
        {
            [Key]
            [DataMember]
            public string TableName { get; set; }

            [DataMember]
            public string DataTableName { get; set; }


            [DataMember]
            public string DataSetName { get; set; }

            [Include]
            [Association("ListColumns", "DataTableName", "DataTableName")]
            [DataMember]
            public Collection<DataColumnInfo> Columns { get; set; }

        }

        [Serializable()]
        [DataContract]
        public class DataColumnInfo
        {
            [Key]
            [DataMember]
            public string ColumnName { get; set; }

            [DataMember]
            public string TableName { get; set; }

            [DataMember]
            public string DataTableName { get; set; }

            [DataMember]
            public string ColumnTitle { get; set; }

            [DataMember]
            public string DataTypeName { get; set; }

            [DataMember]
            public bool IsRequired { get; set; }

            [DataMember]
            public bool IsKey { get; set; }

            [DataMember]
            public bool IsReadOnly { get; set; }

            [DataMember]
            public int DisplayIndex { get; set; }

            [DataMember]
            public string EditControlType { get; set; }

            [DataMember]
            public int MaxLength { get; set; }
        }

     

    In BusinessService  i am using those Classes :

     

     public DataSetData getsampleresult()
            {
                DataSet ds;
                SqlCommand cmd = null;
                SqlConnection conn = new SqlConnection(//Connection string);
                string cmdText = "Select * from emp";
                cmd = new SqlCommand(cmdText, conn);
                if (cmdText.ToString() == "")
                    return null;
                else
                {
                    conn.Open();
                    SqlDataAdapter adapter = new SqlDataAdapter();
                    adapter.SelectCommand = new SqlCommand(cmdText);
                    adapter.SelectCommand.Connection = conn;
                    ds = new DataSet();
                    adapter.Fill(ds, "Data");
                    conn.Close();
                    //return DataSetData.FromDataSet(ds);
                    DataSetData dsd = new DataSetData();
                    dsd.Tables = new Collection<DataTableInfo>();
                    foreach (DataTable t in ds.Tables)
                    {
                        DataTableInfo tableInfo = new DataTableInfo { TableName = t.TableName };
                        dsd.Tables.Add(tableInfo);
                        tableInfo.Columns = new Collection<DataColumnInfo>();
                        foreach (DataColumn c in t.Columns)
                        {
                            DataColumnInfo col = new DataColumnInfo { ColumnName = c.ColumnName, ColumnTitle = c.ColumnName, DataTypeName = c.DataType.FullName, MaxLength = c.MaxLength, IsKey = c.Unique, IsReadOnly = (c.Unique || c.ReadOnly), IsRequired = !c.AllowDBNull };
                            if (c.DataType == typeof(System.Guid))
                            {
                                col.IsReadOnly = true;
                                col.DisplayIndex = -1;
                            }
                            tableInfo.Columns.Add(col);
                        }
                    }
                    dsd.DataXML = ds.GetXml();
                    return dsd;
                }
            }

     

    I am getting that XML in Front End using ria services:

     

      //Get Search Results         
                clientproxy.DomainContext.Load<DataSetData>(clientproxy.DomainContext.getsampleresult(),
                    LoadBehavior.RefreshCurrent,
                    (LoadOperation<DataSetData> vals) =>
                    {
                        if (!vals.HasError)
                        {
                             DataSetData data = vals.Entities.FirstOrDefault();
                             IEnumerable list = DynamicDataBuilder.GetDataList(data);
                             searchViewModel.SearchResults = list;
                             DataTableInfo tableInfo = data.Tables.FirstOrDefault();
                             EntityCollection<DataColumnInfo> columns = tableInfo.Columns;
                             this.SearchResultsDataGrid.Columns.Clear();
                             PagedCollectionView tempListView = new PagedCollectionView(DynamicDataBuilder.GetDataList(data));
                             SearchResultsDataGrid.ItemsSource = tempListView;
                             SearchResultsPager.Source = tempListView;
                            if (data.Tables.Count > 0)
                            {
                                SearchResultsPager.Visibility = Visibility.Visible;
                                foreach (DataColumnInfo column in columns)
                                {
                                    if (column.DisplayIndex != -1)
                                    {
                                        DataGridColumn col;
                                        if (column.DataTypeName == typeof(bool).FullName)
                                        {
                                            DataGridCheckBoxColumn checkBoxColumn = new DataGridCheckBoxColumn();
                                            checkBoxColumn.Binding = new Binding(column.ColumnName);
                                            col = checkBoxColumn;
                                        }
                                        else
                                        {
                                            DataGridTextColumn textColumn = new DataGridTextColumn();
                                            textColumn.Binding = new Binding(column.ColumnName);
                                            textColumn.Binding.ValidatesOnExceptions = true;
                                            col = textColumn;
                                        }

                                        col.Header = column.ColumnTitle;
                                        col.SortMemberPath = column.ColumnName;
                                        SearchResultsDataGrid.Columns.Add(col);
                                    }
                                }
                            }
                            SearchResultsDataGrid.CanUserReorderColumns = false;
                            SearchResultsDataGrid.FrozenColumnCount = 2;
                            SearchResultsDataGrid.HorizontalContentAlignment = HorizontalAlignment.Center; 
                          
                        }
                    }, null);

     In Sladpater solution we have 2 classes under Util folder

    1.DataObject.cs

    2.DynamicDataBuilder.cs

     

    You need to add those 2 in front end module.Those 2 are used to parse the XML:

     

    You need to change some code under DynamicDataBuilder class like this

     

      DataTableInfo tableInfo = data.Tables.FirstOrDefault();
                var observableCollection = new ObservableCollection<DataColumnInfo>();
                System.Windows.Ria.EntityCollection<DataColumnInfo> columns = tableInfo.Columns;
                foreach (var item in columns)
                    observableCollection.Add((DataColumnInfo)item);

                System.Type dataType = BuildDataObjectType(observableCollection, "MyDataObject");

     

     

     This is the how i make it work sladapter solution with RIA services

     

     

    Thanks

    Saritha

    Friday, April 30, 2010 2:41 PM
  • The below link contains compiled SL4 RIA Services project, using Sladpater's technique & Saritha
    's changings for caling SQL query from DomainService.

    http://rapidshare.com/files/382346273/SQLQuery.rar.html

    Just one thing I m using foreach loop, as I was getting error on

    DataSetData data = vals.Entities.FirstOrDefault();  //  No method found FirstOrDefault();

    so I am using

               foreach(DataSetData d in vals.Entities)  // as there is only one entity , so this loop runs only once.
                    {
                        data = d;
                    }

    Thanks Sladpater & Saritha.

    Sunny

    Saturday, May 01, 2010 12:03 PM
  • You need to include System.Linq to use the following Syntax:

     DataSetData data = vals.Entities.FirstOrDefault();

    Saturday, May 01, 2010 1:08 PM
  • Yes , u r right.

    Thanks Sladapter.

    Sunny

    Sunday, May 02, 2010 1:30 AM
  •  

    Monday, May 03, 2010 3:00 PM
  • Saritha,

    In my application, administrators must be able to configure the columns shown on a datagrid for a given installation.  So, I have created several metadata tables to store information about the data grids.  The two tables pertinent to hyperlinks I called "UI_DynamicDataGridColumns" and "UI_URL_Parameters".

    The UI_DynamicDataGridColumns table contains columns like ColumnName, Alias, OrderInDataGrid, and RelativeURL.  The RelativeURL is where I store the URL for the hyperlinks in that column to use, Ex: "../reporting/myreport.aspx".

    The UI_URL_Parameters table stores a list of parameters that must be added to the relative URL for that column. This table has columns like "ParameterName", "ParameterColumnName" (the column to use from the data query), and "FixedValue". So, for example, if column1 in my grid was a hyperlink with two parameters, the parameter entries might look something like this:

    ParameterName................ParameterColumnName.............FixedValue

    GraphType............................NULL......................................BarGraph

    ItemID............................................ID..................................NULL

    I then have a scalar function that I call when loading the grid that builds the URL with the parameters.  It grabs the relativeURL and loops for each of the parameters and adds them to the URL.  If the parameter has a fixed value the value is simply added to the URL; if the parameter has a "parameterColumnName" defined instead, a placeholder will be put in in brackets.  So, for the above, it would be something like this: "../reporting/myreport.aspx?GraphType=BarGraph&ItemID={ID}".  So, the graph type is the same for all rows in that column on the grid, but ID will be different for each row.

    This information is brought into my business layer by a stored procedure and loaded into the DataColumnInfo class. I have added a "URL" property to the DataColumnInfo to hold the URL created above. From here, ideally, I would like to simply load that for the URL of each column when I dynamically create the column datatemplate, and use a value converter to replace the parameter placeholders for each column (the {ID} bit in the above example).  However, I have not figured out how to feed the plain text URL into the data template and allow it to bind to the ID column. I just get errors.  So, I have had to use the following workaround:

    I run two database queries. The first retrieves the metadata for the columns including the URL as described above. The second retrieves the data for the grid using the metadata tables I created to determine which columns to grab (remember this is configurable by an admin). This includes columns used in the URLs. So, in the example above, the ID column would be grabbed even though it isn't shown, because it's value will be used in the URL for each row.

    In the DataSetData class, I then loop through each data row and replace the parameter placeholders in the URL with the data from the appropriate columns in the dataset. So, for the URL above, for each row, I would replace "{ID}" with the value in the ID column of the dataset for that row.  Also, remember the URL stored in the database was a relative URL. So, I use System.Web.HttpContext.Current.Request.Url.AbsoluteUri to get the base Uri and use some string manipulation to tack that on to my relative URL from the DB.

     

    //Build URL
                                string absoluteURL = System.Web.HttpContext.Current.Request.Url.AbsoluteUri;
                                absoluteURL = absoluteURL.Substring(0, absoluteURL.LastIndexOf('/'));//Trim everything from the last "/" on.
                                row[urlColumnName] = absoluteURL + relativeURL.TrimStart('.');
     

    At this point the URL is completely build (no need for a value converter); it just needs to be passed to the client. To make this work for every row, I have had to add a new column for each hyperlink column to the dataset before it is send to the client. I name them "URL-<ColumnName>" so I know what column they go to.  Then, in the code behind for the data grid, when importing the data templates & doing find & replace, I simply bind the NavigateUri of the hyperlink to the "URL-<ColumnName>" column.

    So, there it is. It certainly isn't the prettiest workaround, but at least it works for the time being.  If anyone could tell my how to feed a plain text URL as the NavigateUri for a hyperlink AND bind to a column for the parameter, the workaround would be unecessary.  Perhaps my Silverlight Kung Fu is not strong enough.

    In any case, I hope that helps. Below are code for the method I added to the DataSetData class and my code for the data template creation:

     

    public static DataSetData FromDataSetAndMetaData(DataSet ds, DataSet metaData)
        {
            DataSetData dsd = new DataSetData();
            dsd.Tables = new ObservableCollection<DataTableInfo>();
    
            DataTableInfo tableInfo = new DataTableInfo { TableName = metaData.Tables[0].TableName };
            dsd.Tables.Add(tableInfo);
            tableInfo.Columns = new ObservableCollection<DataColumnInfo>();
    
            //Grab first portion of column definition from MetaData tables
            foreach (DataRow row in metaData.Tables[0].Rows)
            {
                DataColumnInfo column = new DataColumnInfo();
                column.ColumnName = row["ColumnName"].ToString();
                column.ColumnTitle = row["Alias"].ToString();
                column.URL = row["RelativeURL"].ToString();
                column.BackgroundColorColumnName = row["BackgroundColorColumnName"].ToString();
                column.Width = row["Width"].ToString();
                column.MinWidth = row["MinWidth"].ToString();
                tableInfo.Columns.Add(column);
            }
    
            //Grab second portion of column definition from column attributes
            foreach (DataTable table in ds.Tables)
            {
                DataTable URLsTable = new DataTable();
    
                foreach (DataColumnInfo columnFromMetaData in tableInfo.Columns)
                {
                    if (!string.IsNullOrEmpty(columnFromMetaData.URL))
                    {
                        table.Columns.Add("URL_" + columnFromMetaData.ColumnName, typeof(string));
                    }
                }
    
                foreach (DataColumn columnFromData in table.Columns)
                {
                    bool foundColumn = false;
    
                    
                    foreach (DataColumnInfo columnFromMetaData in tableInfo.Columns)
                    {
                        //Add parameters to hyperlinks
                        //Note: this is a workaround because the silverlight tags must have a column to bind to for the URL of each row
                        //and will not take plain text into the converter.
                        //This adds a new URL column to the result set for each existing column that must be a hyperlink.
                        //The new URL column is named "URL-&lt;ColumnName&gt;" and will be searched for as such in the DynamicDataGrid class.
                        if (!string.IsNullOrEmpty(columnFromMetaData.URL))
                        {
                            string urlColumnName = "URL_" + columnFromMetaData.ColumnName;
    
                            System.Text.RegularExpressions.Regex x = new System.Text.RegularExpressions.Regex("{\\w*}");
                            System.Text.RegularExpressions.MatchCollection matches = x.Matches(columnFromMetaData.URL);
    
                            foreach (DataRow row in table.Rows)
                            {
                                string relativeURL = columnFromMetaData.URL;
    
                                //Replace parameter placeholders
                                foreach (System.Text.RegularExpressions.Group group in matches)
                                {
                                    string parameterColumnName = group.Value.Trim(new char[] {'{','}'}); //Remove brackets from parameter column name
                                    relativeURL = relativeURL.Replace(group.Value, row[parameterColumnName].ToString());
                                }
    
                                //Build URL
                                string absoluteURL = System.Web.HttpContext.Current.Request.Url.AbsoluteUri;
                                absoluteURL = absoluteURL.Substring(0, absoluteURL.LastIndexOf('/'));//Trim everything from the last "/" on.
                                row[urlColumnName] = absoluteURL + relativeURL.TrimStart('.');
                            }
                        }
    
                        //Add visible columns
                        if (columnFromMetaData.ColumnName == columnFromData.ColumnName)
                        {
                            foundColumn = true;
    
                            columnFromMetaData.DataTypeName = columnFromData.DataType.FullName;
                            columnFromMetaData.MaxLength = columnFromData.MaxLength;
                            columnFromMetaData.IsKey = columnFromData.Unique;
                            columnFromMetaData.IsReadOnly = (columnFromData.Unique || columnFromData.ReadOnly);
                            columnFromMetaData.IsRequired = !columnFromData.AllowDBNull;
    
                            if (columnFromData.DataType == typeof(System.Guid))
                            {
                                columnFromMetaData.IsReadOnly = true;
                                columnFromMetaData.DisplayIndex = -1;
                            }
    
                            break;
                        }
                    }
    
                    //Add nonvisible helper columns (URL parameters, background colors, etc.)
                    if (!foundColumn)
                    {
                        DataColumnInfo nonvisibleColumn = new DataColumnInfo();
                        nonvisibleColumn.ColumnName = columnFromData.ColumnName;
                        nonvisibleColumn.ColumnTitle = columnFromData.ColumnName;
                        nonvisibleColumn.DataTypeName = columnFromData.DataType.FullName;
                        nonvisibleColumn.MaxLength = columnFromData.MaxLength;
                        nonvisibleColumn.IsKey = columnFromData.Unique;
                        nonvisibleColumn.IsReadOnly = (columnFromData.Unique || columnFromData.ReadOnly);
                        nonvisibleColumn.IsRequired = !columnFromData.AllowDBNull;
                        nonvisibleColumn.DisplayIndex = -1;//Hides column
                        tableInfo.Columns.Add(nonvisibleColumn);
                    }
                }
            }
            dsd.DataXML = ds.GetXml();
            return dsd;
        }

    Data Template:

    <DataTemplate x:Name="HyperlinkCell" xmlns='http://schemas.microsoft.com/client/2007'
    				  xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
    	<Grid @ColorConversionProperty@>
    		<HyperlinkButton NavigateUri="{Binding @NavigateUri@}" Content="{Binding Path='@Content@', Converter={StaticResource @StringConverterName@}, ConverterParameter='@StringFormat@'}" TargetName="@TargetName@"/>
    	</Grid>
    </DataTemplate>

     Data Template string replacement:

    else if (!string.IsNullOrEmpty(column.URL))//Create hyperlinks.
                                {
                                    DataGridTemplateColumn hyperlinkColumn = new DataGridTemplateColumn();
                                    string temp = TemplateManager.DataTemplates["HyperlinkCellTemplate"];
                                    if (!string.IsNullOrEmpty(column.BackgroundColorColumnName))
                                    {
                                        temp = temp.Replace("@ColorConversionProperty@", "Background=\"{Binding " + column.BackgroundColorColumnName + ",Converter={StaticResource " + this.ColorConverterName + "}}\"");
                                    }
                                    else
                                    {
                                        temp = temp.Replace("@ColorConversionProperty@", "");
                                    }
                                    temp = temp.Replace("@NavigateUri@", "URL_" + column.ColumnName);//The URL_ columns are added in the DataSetData class, FromDataSetAndMetaData method
                                    temp = temp.Replace("@StringConverterName@", StringConverterName);
                                    temp = temp.Replace("@StringFormat@", "{0}");                                    
                                    temp = temp.Replace("@Content@", column.ColumnName);
                                    temp = temp.Replace("@TargetName@", "_self");
                                    
                                    dt = XamlReader.Load(temp) as DataTemplate;
                                    hyperlinkColumn.CellTemplate = dt;
                                    col = hyperlinkColumn;
                                }
     
    Monday, May 03, 2010 11:05 PM
  • Saritha,

    In my application, administrators must be able to configure the columns shown on a datagrid for a given installation.  So, I have created several metadata tables to store information about the data grids.  The two tables pertinent to hyperlinks I called "UI_DynamicDataGridColumns" and "UI_URL_Parameters".

    The UI_DynamicDataGridColumns table contains columns like ColumnName, Alias, OrderInDataGrid, and RelativeURL.  The RelativeURL is where I store the URL for the hyperlinks in that column to use, Ex: "../reporting/myreport.aspx".

    The UI_URL_Parameters table stores a list of parameters that must be added to the relative URL for that column. This table has columns like "ParameterName", "ParameterColumnName" (the column to use from the data query), and "FixedValue". So, for example, if column1 in my grid was a hyperlink with two parameters, the parameter entries might look something like this:

    ParameterName................ParameterColumnName.............FixedValue

    GraphType............................NULL......................................BarGraph

    ItemID............................................ID..................................NULL

    I then have a scalar function that I call when loading the grid that builds the URL with the parameters.  It grabs the relativeURL and loops for each of the parameters and adds them to the URL.  If the parameter has a fixed value the value is simply added to the URL; if the parameter has a "parameterColumnName" defined instead, a placeholder will be put in in brackets.  So, for the above, it would be something like this: "../reporting/myreport.aspx?GraphType=BarGraph&ItemID={ID}".  So, the graph type is the same for all rows in that column on the grid, but ID will be different for each row.

    This information is brought into my business layer by a stored procedure and loaded into the DataColumnInfo class. I have added a "URL" property to the DataColumnInfo to hold the URL created above. From here, ideally, I would like to simply load that for the URL of each column when I dynamically create the column datatemplate, and use a value converter to replace the parameter placeholders for each column (the {ID} bit in the above example).  However, I have not figured out how to feed the plain text URL into the data template and allow it to bind to the ID column. I just get errors.  So, I have had to use the following workaround:

    I run two database queries. The first retrieves the metadata for the columns including the URL as described above. The second retrieves the data for the grid using the metadata tables I created to determine which columns to grab (remember this is configurable by an admin). This includes columns used in the URLs. So, in the example above, the ID column would be grabbed even though it isn't shown, because it's value will be used in the URL for each row.

    In the DataSetData class, I then loop through each data row and replace the parameter placeholders in the URL with the data from the appropriate columns in the dataset. So, for the URL above, for each row, I would replace "{ID}" with the value in the ID column of the dataset for that row.  Also, remember the URL stored in the database was a relative URL. So, I use System.Web.HttpContext.Current.Request.Url.AbsoluteUri to get the base Uri and use some string manipulation to tack that on to my relative URL from the DB.

     

    //Build URL
                                string absoluteURL = System.Web.HttpContext.Current.Request.Url.AbsoluteUri;
                                absoluteURL = absoluteURL.Substring(0, absoluteURL.LastIndexOf('/'));//Trim everything from the last "/" on.
                                row[urlColumnName] = absoluteURL + relativeURL.TrimStart('.');
     

    At this point the URL is completely build (no need for a value converter); it just needs to be passed to the client. To make this work for every row, I have had to add a new column for each hyperlink column to the dataset before it is send to the client. I name them "URL-<ColumnName>" so I know what column they go to.  Then, in the code behind for the data grid, when importing the data templates & doing find & replace, I simply bind the NavigateUri of the hyperlink to the "URL-<ColumnName>" column.

    So, there it is. It certainly isn't the prettiest workaround, but at least it works for the time being.  If anyone could tell my how to feed a plain text URL as the NavigateUri for a hyperlink AND bind to a column for the parameter, the workaround would be unecessary.  Perhaps my Silverlight Kung Fu is not strong enough.

    In any case, I hope that helps. Below are code for the method I added to the DataSetData class and my code for the data template creation:

     

    public static DataSetData FromDataSetAndMetaData(DataSet ds, DataSet metaData)
        {
            DataSetData dsd = new DataSetData();
            dsd.Tables = new ObservableCollection<DataTableInfo>();
    
            DataTableInfo tableInfo = new DataTableInfo { TableName = metaData.Tables[0].TableName };
            dsd.Tables.Add(tableInfo);
            tableInfo.Columns = new ObservableCollection<DataColumnInfo>();
    
            //Grab first portion of column definition from MetaData tables
            foreach (DataRow row in metaData.Tables[0].Rows)
            {
                DataColumnInfo column = new DataColumnInfo();
                column.ColumnName = row["ColumnName"].ToString();
                column.ColumnTitle = row["Alias"].ToString();
                column.URL = row["RelativeURL"].ToString();
                column.BackgroundColorColumnName = row["BackgroundColorColumnName"].ToString();
                column.Width = row["Width"].ToString();
                column.MinWidth = row["MinWidth"].ToString();
                tableInfo.Columns.Add(column);
            }
    
            //Grab second portion of column definition from column attributes
            foreach (DataTable table in ds.Tables)
            {
                DataTable URLsTable = new DataTable();
    
                foreach (DataColumnInfo columnFromMetaData in tableInfo.Columns)
                {
                    if (!string.IsNullOrEmpty(columnFromMetaData.URL))
                    {
                        table.Columns.Add("URL_" + columnFromMetaData.ColumnName, typeof(string));
                    }
                }
    
                foreach (DataColumn columnFromData in table.Columns)
                {
                    bool foundColumn = false;
    
                    
                    foreach (DataColumnInfo columnFromMetaData in tableInfo.Columns)
                    {
                        //Add parameters to hyperlinks
                        //Note: this is a workaround because the silverlight tags must have a column to bind to for the URL of each row
                        //and will not take plain text into the converter.
                        //This adds a new URL column to the result set for each existing column that must be a hyperlink.
                        //The new URL column is named "URL-&lt;ColumnName&gt;" and will be searched for as such in the DynamicDataGrid class.
                        if (!string.IsNullOrEmpty(columnFromMetaData.URL))
                        {
                            string urlColumnName = "URL_" + columnFromMetaData.ColumnName;
    
                            System.Text.RegularExpressions.Regex x = new System.Text.RegularExpressions.Regex("{\\w*}");
                            System.Text.RegularExpressions.MatchCollection matches = x.Matches(columnFromMetaData.URL);
    
                            foreach (DataRow row in table.Rows)
                            {
                                string relativeURL = columnFromMetaData.URL;
    
                                //Replace parameter placeholders
                                foreach (System.Text.RegularExpressions.Group group in matches)
                                {
                                    string parameterColumnName = group.Value.Trim(new char[] {'{','}'}); //Remove brackets from parameter column name
                                    relativeURL = relativeURL.Replace(group.Value, row[parameterColumnName].ToString());
                                }
    
                                //Build URL
                                string absoluteURL = System.Web.HttpContext.Current.Request.Url.AbsoluteUri;
                                absoluteURL = absoluteURL.Substring(0, absoluteURL.LastIndexOf('/'));//Trim everything from the last "/" on.
                                row[urlColumnName] = absoluteURL + relativeURL.TrimStart('.');
                            }
                        }
    
                        //Add visible columns
                        if (columnFromMetaData.ColumnName == columnFromData.ColumnName)
                        {
                            foundColumn = true;
    
                            columnFromMetaData.DataTypeName = columnFromData.DataType.FullName;
                            columnFromMetaData.MaxLength = columnFromData.MaxLength;
                            columnFromMetaData.IsKey = columnFromData.Unique;
                            columnFromMetaData.IsReadOnly = (columnFromData.Unique || columnFromData.ReadOnly);
                            columnFromMetaData.IsRequired = !columnFromData.AllowDBNull;
    
                            if (columnFromData.DataType == typeof(System.Guid))
                            {
                                columnFromMetaData.IsReadOnly = true;
                                columnFromMetaData.DisplayIndex = -1;
                            }
    
                            break;
                        }
                    }
    
                    //Add nonvisible helper columns (URL parameters, background colors, etc.)
                    if (!foundColumn)
                    {
                        DataColumnInfo nonvisibleColumn = new DataColumnInfo();
                        nonvisibleColumn.ColumnName = columnFromData.ColumnName;
                        nonvisibleColumn.ColumnTitle = columnFromData.ColumnName;
                        nonvisibleColumn.DataTypeName = columnFromData.DataType.FullName;
                        nonvisibleColumn.MaxLength = columnFromData.MaxLength;
                        nonvisibleColumn.IsKey = columnFromData.Unique;
                        nonvisibleColumn.IsReadOnly = (columnFromData.Unique || columnFromData.ReadOnly);
                        nonvisibleColumn.IsRequired = !columnFromData.AllowDBNull;
                        nonvisibleColumn.DisplayIndex = -1;//Hides column
                        tableInfo.Columns.Add(nonvisibleColumn);
                    }
                }
            }
            dsd.DataXML = ds.GetXml();
            return dsd;
        }

    Data Template:

    <DataTemplate x:Name="HyperlinkCell" xmlns='http://schemas.microsoft.com/client/2007'
    				  xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
    	<Grid @ColorConversionProperty@>
    		<HyperlinkButton NavigateUri="{Binding @NavigateUri@}" Content="{Binding Path='@Content@', Converter={StaticResource @StringConverterName@}, ConverterParameter='@StringFormat@'}" TargetName="@TargetName@"/>
    	</Grid>
    </DataTemplate>

     Data Template string replacement:

    else if (!string.IsNullOrEmpty(column.URL))//Create hyperlinks.
                                {
                                    DataGridTemplateColumn hyperlinkColumn = new DataGridTemplateColumn();
                                    string temp = TemplateManager.DataTemplates["HyperlinkCellTemplate"];
                                    if (!string.IsNullOrEmpty(column.BackgroundColorColumnName))
                                    {
                                        temp = temp.Replace("@ColorConversionProperty@", "Background=\"{Binding " + column.BackgroundColorColumnName + ",Converter={StaticResource " + this.ColorConverterName + "}}\"");
                                    }
                                    else
                                    {
                                        temp = temp.Replace("@ColorConversionProperty@", "");
                                    }
                                    temp = temp.Replace("@NavigateUri@", "URL_" + column.ColumnName);//The URL_ columns are added in the DataSetData class, FromDataSetAndMetaData method
                                    temp = temp.Replace("@UriConverterName@", UriConverterName);
                                    temp = temp.Replace("@UriConverterParameter@", "");
                                    temp = temp.Replace("@StringConverterName@", StringConverterName);
                                    temp = temp.Replace("@StringFormat@", "{0}");                                    
                                    temp = temp.Replace("@Content@", column.ColumnName);
                                    temp = temp.Replace("@TargetName@", "_self");
                                    
                                    dt = XamlReader.Load(temp) as DataTemplate;
                                    hyperlinkColumn.CellTemplate = dt;
                                    col = hyperlinkColumn;
                                }
     
    Monday, May 03, 2010 11:05 PM
  • In the last code sample on my previous post, please ignore the "UriConverter" & "UriConverterParameter" replacements.  These are not used.  I simply forgot to take them out.

    Monday, May 03, 2010 11:09 PM
  • Hi Sladpater,

    i have one doubt regarding saving.

    Since i am using dynamic query i may get data from different tables.Can you give me some idea how can i save data in that case? 

     

     

     

    Thanks

    Saritha

    Wednesday, May 05, 2010 9:29 AM
  • You can use ADO.NET DataSet batch update, but you still need to indicate which table to update.

    http://msdn.microsoft.com/en-us/library/ms810297.aspx

    You can use SqlCommandBuilder to build Update/Insert/Delete command based on the Select SQL.  So on your DataSetData you should add a SelectSQL property to remember the select SQL. 

    This is really not a Silverlight question. If you used DataSet in any windows app or ASP.NET app, you should have the same problem, and how did you handle update when you used DataSet before?

     

     

     

     

    Wednesday, May 05, 2010 10:07 AM
  • Quick question:

    I've taken this Dynamic DataGrid and encapsulated it in a custom control.  It would seem the simplest way to keep this generic & reusable would be to allow pages using the control to simply pass in the SQL command they wish to run from their page.xaml.cs.  Does this present a security issue?

    Thanks,

    Joseph

    Monday, May 10, 2010 11:17 AM
  • What do you mean by "security issue" here? You mean the capability of directly passing SQL statement to your Server?

    Monday, May 10, 2010 11:26 AM
  • Correct.  If understand things correctly, the page.xaml.cs is sent to the client.  By having that file send a SQL command through the custom control back to my web service, do I open up the possibility of SQL injection attacks?

    Note: the SQL string would be hardcoded in the cs file, but may include parameters from the query string. I believe that, generally, a parameterized SQLCommand should be used to avoid SQL injection in this type of situation, correct?  But, SQLCommand does not appear to be available in Silverlight.

    Monday, May 10, 2010 12:15 PM
  • I guess the other option here is to have the page using my custom control make the webservice call and just pass the DataSetData object to the custom control.  The problem is that the DataSetData type returned is tied to the Service Reference.  I have seen two solutions for working around this problem.  One is to create a local object in the custom control and assign one to one (a bit of a hack in my opinion).  The other is to serialize to XML in the service & deserialize in the custom control. This may be a bit cleaner, but also adds an additional level of processing to every query.

    So, as far as I can tell, my two foremost options are having the page using the custom control pass a SQL query through the custom control. Or, I could have the container page make the webservice call itself and pass the serialized results to the custom control to deserialize.

    Thoughts?

    Monday, May 10, 2010 1:46 PM
  • Yes, if your app can pass SQL string back to server and to be executed directly,  your app certainly has the vulnerability for SQL injection attack.

    My demo only servers as a proof of concept for displaying any data that is dynamically generated. In reality you do not want user input any SQL statement in your Web App to be sent back and executed directly. You probably want to pass some kind of Filter object back to server, then you can build the parametrized SQL command based on this Filter object to be executed.

     

     

     

    Monday, May 10, 2010 2:51 PM
  •  Hi Sladapter,

     This is not related to datagrid but silverlight questions.

    In my project for each module i have a search buttoon.Search Functionlaity is defined in seperate module.All search Buttons needs to hook up with Searchpanel.XML in search module.

    Can you please give a suggesstion to achive this ?

     

    Thanks

    Saritha

    Monday, May 10, 2010 5:20 PM
  • Maybe you should start another thread. This one is already getting too long, and we don't want to deviate the main discussion by some non related issues.

    Monday, May 10, 2010 5:42 PM
  • I recomment writing a simple workflow engine on the backend. For example: to read data I'll send a list of key-values(JSON string) which define a Workflow name and any filter values that I want and I'll return a dataset as a result.

    To Update data, I send the name of the workflow and dataset.

    My workflows are themselves datasets saved as files.  I loop thru rows executing methods with parameters.

    One method may be to set the connection string for MSSQL or Oracle, another sets the select statement and another sets the table name. Then I fill the dataset. I may continue with more tables even adding relations before finally returning the dataset to the client.

    I can define a workflow without doing any coding on the backend.

    Tuesday, May 11, 2010 9:32 AM
  •  Hi,

    I am having very weird problem, I have DataColumnInfo class in my web project as 

     [Serializable()]
    [DataContract]
    public class DataColumnInfo
    {
    [Key]
    [DataMember]
    public string ColumnName { get; set; }

    [DataMember]
    public string TableName { get; set; }

    [DataMember]
    public string DataTableName { get; set; }

    [DataMember]
    public string ColumnTitle { get; set; }

    [DataMember]
    public string DataTypeName { get; set; }

    [DataMember]
    public bool IsRequired { get; set; }

    [DataMember]
    public bool IsKey { get; set; }

    [DataMember]
    public bool IsReadOnly { get; set; }

    [DataMember]
    public int DisplayIndex { get; set; }

    [DataMember]
    public string EditControlType { get; set; }

    [DataMember]
    public int MaxLength { get; set; }
     

     as Saritha has told.

    But in my auto generated code 'TstProj.Web.g.cs' at Silverlight client side, I cannot find code for 'DataColumnInfo' or 'DataSetData' classes required in 'DynamicDataBuilder' class.So its giving me error of missing type or namespace  on 'DataColumnInfo' .

    I have tested this in new silverlight project as well but same issue, I have even restarted my machine, but samething is happening .

    Any one got clue that why it is not autogenerating code for  'DataColumnInfo' or 'DataSetData' ???

    Shah

     

    Wednesday, May 12, 2010 10:19 AM
  • Excellent!

    Just one bug I noticed: If you tab out from a cell (after updating) the program just aborts!  This does not happend if you click update button.

    I will fix it....

    thanks for posting

    Ramesh Bas

    rameshbas@yahoo.com

    Thursday, May 13, 2010 12:52 PM
  • Hi Sladpater,

     

    I ahve one doubt regaridng your Hyperlink Code.I want to create a click event for that.Not getting idea how can we do that.

    Please let me know if you have some thinkg like that

     

     

    Thanks

    Saritha 

    Tuesday, July 20, 2010 4:49 PM
  • To add event on controls defined in CellTemplate, see this thread:

    http://betaforums.silverlight.net/forums/p/167310/388045.aspx

    In DataGrid Loading_Row event you should be able to find the control defined in CellTemplete. Then you can assign event handler on those controls.


    Tuesday, July 20, 2010 8:27 PM
  • Hi ,

    When I set my DataGrid's AutoGenerateColumns to True, it always generate an extra column name 'state' with data like 'Unchanged' with my other table columns. I am doing somthing like this


                    IEnumerable list = DynamicDataBuilder.GetDataList(data);                

                    this.SLGrid.ItemsSource = list; 

    How can I make it to not to auto generate column 'state' in my datagrid ?

    Thanks.

    Sunday, July 25, 2010 4:45 AM
  • Oh, the State is a Property in DataObject that remember the current State of the object. You can add the following Tag to it so it won't be shown in the AutoGenerated column: 

    public class DataObject : INotifyPropertyChanged, IEditableObject
        {

           ...

            [Display(AutoGenerateField = false)]
            public DataStates State { get; set; }

           ...

    }


    Sunday, July 25, 2010 9:46 AM
  • Thanks Sladapter.

    Monday, July 26, 2010 8:24 AM
  • Hi Sladapter ,

    When I try to save my custom class object which has the property IEnumerable List returned from DynamicDataBuilder.GetDataList() function in IsolatedStorage , I get following exception

    "Type 'MyDataObject' with data contract name 'MyDataObject:http://schemas.datacontract.org/2004/07/' is not expected. Add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer."   

    How can I apply KnownTypeAttribute  here ?


    Thanks.


    Thursday, July 29, 2010 2:20 AM
  • Can someone please repost the code for RIA services and SL4 at

    http://rapidshare.com/files/382346273/SQLQuery.rar.html

    Thanks a bunch.

    KG

    Thursday, August 05, 2010 1:40 PM
  • The provider I was working with returns columns with underlying data type System.TimeSpan.  This was blowing up, so I modified DataObject.cs as follows:

     

    public void SetFieldValue(string fieldname, object value)

    {

    PropertyInfo pi = this.GetType().GetProperty(fieldname);

    if (pi != null )

    {

     if (pi.PropertyType.FullName == typeof(System.TimeSpan ).FullName)

    {

     string duration = value.ToString();

     

    if (duration.StartsWith("PT" ) && duration.Contains("H") && duration.Contains("M" ) && duration.EndsWith("S" ))

    {

    duration = duration.Substring(2, duration.Length - 3);

    duration = duration.Replace('H', ':');

    duration = duration.Replace('M', ':');

    }

     TimeSpan ts = TimeSpan.Parse(duration);

    pi.SetValue(this, ts, null

    );

    }

     else

    {

     object pValue = Convert.ChangeType(value, pi.PropertyType, null);

     if (pValue != null)

    pi.SetValue(this, pValue, null);

    }

    }

    }

    Thursday, December 09, 2010 7:19 PM
  • Silverlight 4 supports binding to indexed properties.

    Is Sally's code posted here obsolete ?

    Should code generation be replaced with binding to indexed properties or is code generation still best method to show dynamic properties in DataGrid ?

    Andrus.

     

    Saturday, December 11, 2010 5:22 PM
  • Please provide me the VB code of (Mainly VAR usage in VB ?? !). Please provide the vb equal code.

    public static DataSet ToDataSet(DataSetData dsd)
        {
            DataSet ds = new DataSet();
            UTF8Encoding encoding = new UTF8Encoding();
            Byte[] byteArray = encoding.GetBytes(dsd.DataXML);
            MemoryStream stream = new MemoryStream(byteArray);
            XmlReader reader = new XmlTextReader(stream);
            ds.ReadXml(reader);
            XDocument xd = XDocument.Parse(dsd.DataXML);


            foreach (DataTable dt in ds.Tables)
            {                        
                var rs = from row in xd.Descendants(dt.TableName)
                         select row;            
                 
                int i = 0;
                foreach (var r in rs)
                {
                    DataRowState state = (DataRowState)Enum.Parse(typeof(DataRowState), r.Attribute("RowState").Value);
                    DataRow dr = dt.RowsIdea;
                    dr.AcceptChanges();
                    if (state == DataRowState.Deleted)
                        dr.Delete();
                    else if (state == DataRowState.Added)
                        dr.SetAdded();
                    else if (state == DataRowState.Modified)
                        dr.SetModified();               
                    i++;
                }
            }            
            return ds;
        }

    Tuesday, February 08, 2011 9:05 PM
  • Hello sladapter,

    I have checked couple of other projects and this is the best one.

    Iam looking for same in VB.net.

    Please send me the link for VB code of this project.

    Anyone else who have already invented the wheel also .

    Cheers

    Wednesday, February 09, 2011 5:10 PM
  • I don't have VB code for this. I haven's used VB programming for a long time. You may have to convert it yourself.

    Wednesday, February 09, 2011 5:44 PM
  • Hi, can you send me a demo using this...eventually some that includes dropdwonlist, update, delete, insert usages.Thanks for everithing, you did a great job.

    Here's my hotmail acc: razvan_d7@hotmail.com.

    Wednesday, March 02, 2011 10:01 AM
  • So has anything changed in that area with the release of Silverlight 4? Is there any hope things will change in Silverlight 5?

    Also, does anyone know of any (free or commercial) grid that supports binding to dynamic data (using the propritary interfaces since ITypedList is not part of SL)? The reflection-based approach with creating new types on the fly seems too kludgy to me since the data set will be heavily edited in our case and also we might have thousands of columns.

    -Andrew

    Thursday, March 10, 2011 11:56 AM
  • Hi Andrew,

    You can look at http://silverlightdataset.net/

     

    Thursday, March 10, 2011 1:19 PM
  • But doesn't it create new types on the fly?

    Thursday, March 10, 2011 3:57 PM
  • Yes it does.

    It caches generated dlls for the life cycle of silverlight application.

    Thursday, March 10, 2011 6:35 PM
  • go to http://silverlightdataset.net/ and click on "Demo Application" inside left navigation panel

    Wednesday, March 16, 2011 11:29 AM
  • Unfortunately, constructing a type for any change doesn't look very good for us since the data structure will be constantly changing (columns will be added/removed frequently).

    Thursday, March 17, 2011 2:20 PM
  • You don't need to create any classes manually. Silverlight DataSet takes care about it at runtime

    Thursday, March 17, 2011 3:14 PM
  • I understand it, but code generation whenever data structure changes is not acceptable for us for many reasons (performance, memory usage, etc). Thanks for the nice project, though!

    Friday, March 18, 2011 3:04 PM
  • This is a very frustrating issue. So far, I have found no solutions that actually work. Every time I Google it, I get the same threads. None actually work.

    I have a service that returns a dataset in the form of XML. THE COLUMNS/ELEMENTS ARE NOT KNOWN AT RUNTIME. In other words, I can't build and enumerable or observable list of elements before runtime to bind with the datagrid. 

    I'm beginning to believe that a datagrid is next to useless in Silverlight. And since the internet is about consuming data, I'm wondering if Silverlight is really a good development platform (vs. AJAX or Flash). I really had high hopes for Silverlight but am very disheartened over this issue.

    Thursday, March 24, 2011 8:31 PM
  • This is a very frustrating issue. So far, I have found no solutions that actually work. Every time I Google it, I get the same threads. None actually work.

    Have you tried my solution file? Of course what I provided is only a proof of concept. If you understand the concept, you should be able to extended it and make it work for your case.

    Friday, March 25, 2011 9:56 AM
  • I'm beginning to believe that a datagrid is next to useless in Silverlight. And since the internet is about consuming data, I'm wondering if Silverlight is really a good development platform (vs. AJAX or Flash). I really had high hopes for Silverlight but am very disheartened over this issue.

    This is exactly how I feel.

    By the way, it looks like Syncfusion's grid has proper support for dynamic data:

    http://www.syncfusion.com/products/user-interface-edition/silverlight/grid/griddatacontrol#data-binding

    Data Binding
    The GridDataControl provides out of the box databinding support to all the popular datasources including the DomainDataSource for binding to WCF RIA servies (with ADO.NET’s Entities or LINQ to SQL or any custom data layer as back end), DataTable and DataView, ObservableColletion, CollectionViewSource, all the collections implementing ICollectionView, IEnumerable, IList, IBindingList, IQueryable, ITypedList and ICustomTypeDescriptor. When bound to the DomainDataSource, all the data operations done in the DomainDataSource like Sorting, Paging, Filtering, etc will be reflected in the Grid.

    Friday, March 25, 2011 11:57 AM
  • nice project, now i can look demo at http://silverlightdataset.net/

    useful, thank all                                         

    Sunday, March 27, 2011 12:19 AM
  • Hello Sl4Adaptor

    I tried your sample and try selecting the datagrid row and get one row data. When tried to extract the datagrid1.selecteditem, it returned as ((MyDataObject)).(datagrid1.selectedItem).CustomerName. When i assign it to a string, it says, MyDataObject not available. Is there anyway you can help me resolve this issue?

    Best Regards

    Dhinesh Kumar


    Monday, April 04, 2011 1:47 PM
  • I tried your sample and try selecting the datagrid row and get one row data. When tried to extract the datagrid1.selecteditem, it returned as ((MyDataObject)).(datagrid1.selectedItem).CustomerName. When i assign it to a string, it says, MyDataObject not available. Is there anyway you can help me resolve this issue?

    If you want to get CustomerName Field value, you have to do this:

      DataObject data = dg.SelectedItem as DataObject

      if(data != null)

         string name = data.GetFieldValue("CustomerName");



    Monday, April 11, 2011 11:12 AM
  • Hi Sladapter,

    I am using your solution in my WCF RIA Services project , and binding the Datasetdata to my DataGird (Autogenerate columns = true) like this

    DataSetData data = null;
                    data = vals.Entities.FirstOrDefault();

                    IEnumerable list = DynamicDataBuilder.GetDataList(data);

    , if I call my serverside DomainService again with different DB table , it returns me DataSetData and when I bind it to my grid, my gris shows the current DataSetData table columns with previous DataSetData table columns ???

    Important thing to note is that , it only shows the column names of previous DataSetData table, there is no data in rows for these columns.

    Can you please help me solving this issue that why my grid is shwoing old and current DataSetData table columns ???

    Thanks,

    Maverick

    Friday, June 17, 2011 10:55 AM
  • Did you clear the Columns collection when you reset Binding with a new DataSet?

    Because AutoGenerateColumn is turned off,  the Columns collection contains whatever column you put in.  If you reset Binding without clear the Columns collection, it will still contain old columns. Make sure you call DataGrid.Collumns.Clear() before you reset binding.




    Friday, June 17, 2011 11:24 AM

  • Friday, June 17, 2011 12:59 PM
  • I am using AutogenerateColumns = True. And even if I set the 2nd DataSetdata to 2nd grid , it shows the columns of previous datasetdata in that 2nd grid !!!

    I think somehow it is persisting the Columns of previous datasetdata at clientside.... but why and how ?

    Friday, June 17, 2011 1:57 PM
  • What is the LoadBehavior on the Load operation? Did you use LoadBehavior.RefreshCurrent?

    Friday, June 17, 2011 2:14 PM
  • I am calling my domainservice method like this

    EntityQuery<DataSetData> query3 = ds2.getsampleresult_2Query();
                LoadOperation<DataSetData> lo = ds2.Load(query3, LoadBehavior.RefreshCurrent, true);
                lo.Completed += new EventHandler(lo_Completed_2);


     

    And my in callback function

      LoadOperation<DataSetData> vals = sender as LoadOperation<DataSetData>;
                if (!vals.HasError)
                {
                    DataSetData data = null;
                    data = vals.Entities.FirstOrDefault();
    
                    
                    IEnumerable list = DynamicDataBuilder.GetDataList(data);
    

    And then in GetDataList function

    public static IEnumerable GetDataList(DataSetData data)
    		{
    			if (data.Tables.Count() == 0)
    				return null;
    
                DataTableInfo tableInfo = data.Tables.FirstOrDefault();


    here when I do (tableInfo.Columns).Count = 15 , which should be 6 , and it is carrying the 9 columns of previous datasetdata query.

    Which is very weird !!!


     

    Friday, June 17, 2011 3:18 PM
  •  I have found an interesting thing , if I 'new' my domainservice on every call , then it works fine . Like if I change my calling method like this

    ds2 = new DomainService2();
    EntityQuery<DataSetData> query3 = ds2.getsampleresult_2Query();
     LoadOperation
    <DataSetData> lo = ds2.Load(query3, LoadBehavior.RefreshCurrent, true);
     lo.Completed += new EventHandler(lo_Completed_2);

    Sladapter any idea that why is it doing so ?

    Saturday, June 18, 2011 1:45 PM
  • I'm sure it is DomainContext which caches the old data, that's why I asked if the loadbehavior is set to RefreshCurrent. I'll try to test it myself to see what is going on.

    Saturday, June 18, 2011 2:00 PM
  • yeh but I am using LoadBehavior.RefreshCurrent , so how come Domainservice is still maintaining the result in cache ???  if it is then it can be very problematic in other scenraios as well !!!

    Saturday, June 18, 2011 3:04 PM
  • OK, I test with my solution and I don't have the problem you are having.

    What is you Service query function look like? Make sure to give DataSet a different Name if you query different table.

    try this:

    public DataSetData GetSampleData( string Name, ...) // You can pass Name to the query function.
            {
                //Return your DataSetData;            //Set the DataSet with the Name
            }

    Saturday, June 18, 2011 8:08 PM
  • If I rename my DataSetData  like this

    DataSetData dsd = new DataSetData();
    dsd.DataSetName = "dsd_" + tbl;

    Just before return , I can see that dsd.Tables.Count = 1 , and when I recive this datasetdata on clientside like this

    DataSetData data = null;
     data = vals.Entities.FirstOrDefault();

    then my data.Tables.Count = 0. So nothing binds.

    And If I just leave dsd.DataSetName = null , it returns the table on client side but with my original problem.

    Can you please share your RIA Services Solution ? May be while collecting the code from various posts on this thread , I have missed something

    Thanks.


    Sunday, June 19, 2011 2:55 AM
  • I think I have found the solution.
    If you set your domainservice EntityConatiner.Clear and load with loadbehaviour.RefreshCurrent , then it loads only the correct columns.


                ds2.EntityContainer.Clear();      
                LoadOperation<DataSetData> lo = ds2.Load(query3,LoadBehavior.RefreshCurrent, true);


    Any Idea how can I implement Paging with this dataset ? I can attach DataPager, but it loads all the records from DB and show the rows mentioned in it PageSize. 

    But If I want to use DomainDataSource LoadSize kind of thing , how can I implement it using DataSetData ?

    Thanks.

    Monday, June 20, 2011 5:20 AM
  • Thank you so much for this, sladapter. Really saved my day.

    I was able to convert this to VB.NET after som struggle, and everything seems to be working except for the GetDataSetDataCompletedEventArgs ServerError parameter which is not working correctly for some reason. I did not take the time to investigate the problem, probably just a quick adjustment.

    So anyone looking for a VB.NET version of this can take a look at DataSetInDataGrid_VB_20110829.zip

    I did not convert the code in sladapter's Page.xaml.cs as I used this in a slightly different way.

    Monday, August 29, 2011 3:20 AM