Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to bound a DataGridViewComboBoxColumn to a object?

I'm trying to bound a DataGridViewComboBoxColumn to an instance of Foo, but when i set a value on the grid i got a ArgumentException telling me that i can not convert from String to Foo.

var data = (from item in someTable
            select new { Foo = item.foo, Bar = item.Bar }).ToList();
grid.DataSource = data;
column.DataPropertyName = "Foo";
column.DataSource = (from foo in Foo select foo).ToList (); //foo is an instance of Foo
column.DisplayMember = "SomeNameField"; //Foo.SomeNameField contains a description of the instance

Am i missing something? is it possible to databind to a complex object?

UPDATE:

I implemented a TypeConverter and overrided CanConvertFrom, CanConvertTo, ConvertTo, ConvertFrom. Now i'm getting

FormatException: The DataGridViewComboBoxCell value is not valid

Any ideas?

like image 799
albertein Avatar asked Nov 29 '22 20:11

albertein


2 Answers

the DataGridViewComboBoxColumn should always have all the possible values at the combobox Items list or it will throw "FormatException: The DataGridViewComboBoxCell value is not valid".

If you are trying to get back values chosen from one combobox column, you can handle the DataGridView CellParsing event, and get the selected item from DataGridView.EditingControl cause it will be set for editing control from the edited column. Here is a exemple:

private void dataGridView1_CellParsing(object sender, 
 DataGridViewCellParsingEventArgs e) {
   if (dataGridView1.CurrentCell.OwningColumn is DataGridViewComboBoxColumn) {
       DataGridViewComboBoxEditingControl editingControl = 
                (DataGridViewComboBoxEditingControl)dataGridView1.EditingControl;
       e.Value = editingControl.SelectedItem;
       e.ParsingApplied = true;
   }
}

You also can customize the way your objects are show on each cell by handling the cell Formatting Event, here is a code that display toString for any object or interface.

private void dataGridView1_CellFormatting(object sender, 
    DataGridViewCellFormattingEventArgs e) {
        if (e.Value != null) {
            e.Value = e.Value.ToString();
            e.FormattingApplied = true;
        }
    } 

Handles this two events should be enough for show and edit data within any bussiness object and its easer then write type converters. For this work set you DataGridView and you combobox column as follow:

var data = (from item in someTable
        select new { Foo = item.foo, Bar = item.Bar }).ToList();
grid.DataSource = data;
column.DataPropertyName = "Foo";
column.DataSource = (from foo in Foo select foo).ToList ();

No DisplayMember or ValueMember Property need to be set, just make sure your combobox data source list has all the possible values for Foo.

Hope its helps.

like image 119
Nei Avatar answered Dec 05 '22 01:12

Nei


You are missing a possible piece.

column.DataPropertyName = "Foo";
column.DisplayMember = "SomeNameField"; 
column.ValueMember = "Bar"; // must do this, empty string causes it to be 
                            // of type string, basically the display value
                            // probably a bug in .NET
column.DataSource = from foo in Foo select foo;
grid.DataSource = data;

UPDATE:

Actually, after reading your question again, I think you are facing that noted bug. There is unfortunately no way to make it return the bound object without using a custom TypeDescriptor/TypeConverter/BindingSource.

Answer for binding to a complex object. No by default. I wrote quite a nice one for my current project. This involves making a custom TypeDescriptor/TypeConverter/BindingSource that returns all the nested properties. Another 'bug', you cant use '.' for a member separator, I had to resort to ':' instead.

like image 32
leppie Avatar answered Dec 05 '22 00:12

leppie