2

I have a lot of this working and have created a dropdown and a treeview using this technique. An ajax call to create controls on the fly and return them to the page fully constructed and configured using jqueryajax and C#. But Im stuck on creating a datatable from my class object. The control obviously returns a double looped gridView, I just want it to write out a view of the returned data, eventually with all the goodness of gridView CRUD Ops. Its something simple Im doing wrong can you help?

Here is my C# code for creating a GridView

[WebMethod]
        public static AjaxReturnObject GetProductsByCategoryID(string CategoryID)
        {
            AjaxReturnObject o = new AjaxReturnObject();
            int catID = Convert.ToInt32(CategoryID);
            Product.ProductCollection products = new Product().GetProductsByCategoryID(catID);
            if (products.Count == 0)
            {
                o.Message = "There was no data returned";
                o.Status = 999;

                return o;
            }
            else
            {
                // build a new GridView (or List View) for the UI and populate it with data.
                // 1: Initialize a object of type DataTable.
                DataTable dt = new DataTable();

                //2: Initialize a object of type DataRow
                DataRow drow;

                //3: Initialize enough objects of type DataColumns
                DataColumn col1 = new DataColumn("Product Name", typeof(string));
                DataColumn col2 = new DataColumn("Product Description", typeof(string));
                DataColumn col3 = new DataColumn("Price", typeof(string));
                DataColumn col4 = new DataColumn("Col4", typeof(string));

                //4: Adding DataColumns to DataTable dt
                dt.Columns.Add(col1);
                dt.Columns.Add(col2);
                dt.Columns.Add(col3);
                dt.Columns.Add(col4);

                //5: Adding values in DataColumns       
                for (int i = 0; i < products.Count; i++)
                {

                    foreach (Product item in products)
                    {

                        drow = dt.NewRow();
                        dt.Rows.Add(drow);
                        dt.Rows[i][col1] = item.ProductName.ToString();// i.ToString();
                        dt.Rows[i][col2] = item.ProductDescription.ToString();
                        dt.Rows[i][col3] = String.Format("{0:C}", item.Price);
                        dt.Rows[i][col4] = String.Format("{0:.00}", item.Price);
                    }

                }


                GridView GridView1 = new GridView();
                GridView1.DataSource = dt;
                GridView1.DataBind();


                // Render the new control and return it to the Ajax Return Object
                StringWriter tw = new StringWriter();
                Html32TextWriter writer = new Html32TextWriter(tw);
                GridView1.RenderControl(writer);
                writer.Close();
                o.Object = tw.ToString();


                o.Message = "Result Data Message";
                o.Status = 1;

                return o;
            }
        }
    }
3
  • Do you have debug your code to see if and what is printed at the final point -> o.Object = tw.ToString(); ? Commented Jan 23, 2013 at 10:42
  • Hi Aristos, yes I have the full html for a table in o.Object and display is ok in page, problem is too many loops at //5: Adding values in DataColumns Commented Jan 23, 2013 at 10:49
  • Result is table is very long with empty cells half way down Commented Jan 23, 2013 at 11:14

3 Answers 3

2

Though the above answer is right.

But a better way would be to write extension method which converts the collection to DataTable and we can use it anywhere in the application, i have one in my project which is used to Convert List<T> to DataTable.

Here it goes:

public static class ListExtensions
{
   public static DataTable ToDataTable<T>(this List<T> iList)
   {
    DataTable dataTable = new DataTable();
    PropertyDescriptorCollection propertyDescriptorCollection =
        TypeDescriptor.GetProperties(typeof(T));
    for (int i = 0; i < propertyDescriptorCollection.Count; i++)
    {
        PropertyDescriptor propertyDescriptor = propertyDescriptorCollection[i];
        Type type = propertyDescriptor.PropertyType;

        if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
            type = Nullable.GetUnderlyingType(type);


        dataTable.Columns.Add(propertyDescriptor.Name, type);
    }
    object[] values = new object[propertyDescriptorCollection.Count];
    foreach (T iListItem in iList)
    {
        for (int i = 0; i < values.Length; i++)
        {
            values[i] = propertyDescriptorCollection[i].GetValue(iListItem);
        }
        dataTable.Rows.Add(values);
    }
    return dataTable;
  }
}

and just use it on any List<T> this way:

List<Product> products = new List<Product>();
DataTable dtProducts = products.ToDataTable();
Sign up to request clarification or add additional context in comments.

Comments

1

I believe that you have make a mistake on the loop

// remove that line
// for (int i = 0; i < products.Count; i++)
int i = 0;
{    
    foreach (Product item in products)
    {    
        drow = dt.NewRow();
        dt.Rows.Add(drow);
        dt.Rows[i][col1] = item.ProductName.ToString();// i.ToString();
        dt.Rows[i][col2] = item.ProductDescription.ToString();
        dt.Rows[i][col3] = String.Format("{0:C}", item.Price);
        dt.Rows[i][col4] = String.Format("{0:.00}", item.Price);
        // and here move to next
        i++;
    }    
}

1 Comment

Aristos, it works a treat. Thank you so much. This technique seems to be very fast to return fully constructed controls on the fly, I hope I can complete a gridview fully. Do you see any technical issues or best practice advice for this use?
0

You are running unnecessary foreach loop. Change you looping structure as below :

//5: Adding values in DataColumns       
                for (int i = 0; i < products.Count; i++)
                {

                    //foreach (Product item in products)
                    //{
                    Product item = products[i];
                    drow = dt.NewRow();
                    dt.Rows.Add(drow);
                    dt.Rows[i][col1] = item.ProductName.ToString();// i.ToString();
                    dt.Rows[i][col2] = item.ProductDescription.ToString();
                    dt.Rows[i][col3] = String.Format("{0:C}", item.Price);
                    dt.Rows[i][col4] = String.Format("{0:.00}", item.Price);
                    //}

                }

3 Comments

Hi Gaurav thanks for your reply - Product item = products[i]; produces Null Reference Ex for item at item.ProductName etc...
@Kev: It must work as working here correctly because item is initialized by ith item of products collection. Anyway approach suggested by Aristos is the another approach to serve your purpose,glad to find that your problem is resolved. I have a query regarding optimization of your code that why you are converting from collection to DataTable then binding this dt object to gridview, i mean what if you bind direct collection to gridview. If formatting is required then you can change structure of Product class.
Yes I was binding collection directly with good results, but needed to format the columns, this is why DataTable needed -Thanks

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.