Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert Datagridview's DataSource to List?

I'm trying to write a generic function that will convert a datagridview's datasource to a list (then I want to add an empty object to the list. The datasource could be of any type)?

Some desperate tries of mine looked like this:

Type datagrid_type = dgv.DataSource.GetType();
List<object> the_source = dgv.DataSource as List<object>;
Convert.ChangeType(the_source, datagrid_type);
Object c = Activator.CreateInstance(datagrid_type);
Convert.ChangeType(c, datagrid_type);
the_source.Add(c);

..but the_source is just null. even if it wasn't it still probably won't work. I'm sure you guys will have a smarter way (one that actually works..) to achieve this.

p.s. I'm using EF to create a list which is the datasource, so casting the datasource to DataTable probably not relevant here

like image 841
BornToCode Avatar asked Nov 05 '12 17:11

BornToCode


3 Answers

I did it in the following way (works only when you use binding datasource)

Create a custom datagridview control and inherit datagridview

public partial class MyGridView : DataGridView

Declare a class that holds columnname, summaryvalue and the format to be shown

    [Serializable]
    public class SummaryDataProperty
    { 
        public string ColumnName { get; set; }
        public string Format { get; set; }
        internal decimal Value { get; set; }
    }

Declare list of summary data property in your MyDataGridView

    public List<SummaryDataProperty> SummaryDataPropertyNames { get; set; }

On Data binding complete, calculate the summary and show it at column header.

  protected override void OnDataBindingComplete(DataGridViewBindingCompleteEventArgs e)
    {
        base.OnDataBindingComplete(e);
        if (SummaryDataPropertyNames.Count > 0)
        {
            if (DataSource is BindingSource)
            {
                var ds = (DataSource as BindingSource);
                foreach (var prop in SummaryDataPropertyNames)
                {
                    prop.Value = 0;
                    var col = this.Columns[prop.ColumnName];
                    foreach (var l in ds.List)
                    {
                        decimal val;
                        if (decimal.TryParse(Convert.ToString(l.GetType().GetProperty(col.DataPropertyName).GetValue(l, null)), out val))
                            prop.Value +=   val;
                    }
                    col.HeaderText = col.HeaderText.Split('[')[0].TrimEnd(' ') + " [" + prop.Value.ToString(prop.Format) + "]";
                }

            }
        }
    }

Since the binding data source gives the list of objects from datasource. Its easy to loop through the binding source list. I don't know how to do this with the object datasource or BindingDatasource.Current. I am still looking for a solution.

like image 71
Esen Avatar answered Oct 18 '22 17:10

Esen


nobody answered me here, so I ended up passing the type to the function, although I would be happier if I could avoid that and let the function determine the correct type

public static void Add_Empty_Row_At_To_Grid<T>(DataGridView dgv)
  {
   List<T> the_source = dgv.DataSource as List<T>;
   T c = (T)Activator.CreateInstance(typeof(T));
   the_source.Add(c);
   }
like image 29
BornToCode Avatar answered Oct 18 '22 15:10

BornToCode


If you want a generic function/method and pass a List of diferent objects you can do this (an example extracted in my app):

public void SaveAll<T>(IEnumerable<T> objects)
{
    foreach (object obj in objects)
    {
        T specificObject = (T)obj;
        Session.Save(specificObject);
    }
    Session.Flush();
}

So, you can call this method with any class object:

List<Product> products = Product.GetAll();
SaveAll<Product>(products);

List<Vendor> vendors = Vendor.GetAll();
SaveAll<Vendor>(vendors);

etc

On the other hands, if you have a DataGridView and you want add a row, you can use a BindingSource as DataGridView's DataSource. Example:

...
private BindingSource Source;
...

private void LoadProducts(List<Product> products)
{
       Source.DataSource = products;
       ProductsDataGrid.DataSource = Source;
}

private void addProductBtn_Click(object sender, EventArgs e)
{
       Source.Add(new Product());
}
like image 23
Cristhian Boujon Avatar answered Oct 18 '22 15:10

Cristhian Boujon