Search code examples
c#listdatagridviewdatagridviewcolumn

Binding a DataGridView to an IBindingList that may contain zero elements


Using C# WinForms in VS 2008 (.Net 3.5)

I am trying to bind a list, that may be empty, to a data grid.

If the list has elements, and AutoGenerateColumns is enabled, the data binds to the list and everything works fine.

However, if the list is empty, or if the list becomes empty (by deleting the last element) nothing at all is display, just the gray background.

If I create the columns manually, such as:

                if (m_DataGrid.AutoGenerateColumns == false)
                {
                    foreach (var pair in objData.PropertyDataTable
                        .Where(pair => pair.Value.IsNative == true
                                    && pair.Value.IsList == false))
                    {
                        string propertyName = pair.Key;
                        PropertyData propertyData = pair.Value;

                        if (propertyData.Type == typeof(bool))
                        {
                            var column = new DataGridViewCheckBoxColumn()
                            {
                                Name = propertyName,
                                HeaderText = propertyName,
                                DataPropertyName = propertyName,
                                ValueType = propertyData.Type,
                            };
                            m_DataGrid.Columns.Add(column);
                        }
                        else
                        {
                            var column = new DataGridViewTextBoxColumn()
                            {
                                Name = propertyName,
                                HeaderText = propertyName,
                                DataPropertyName = propertyName,
                                ValueType = propertyData.Type,
                            };
                            m_DataGrid.Columns.Add(column);
                        }
                    }
                }

The columns appear, and I am able to add a new row, but the data is not actually bound, and no default values for the rows are populated like they normally are when the columns are auto generated.

When I leave the view and return, the added lines remain, but the data is not preserved.

Comparing the auto generated columns to the manually created columns in the debugger, the only property that is different between the two is the IsDataBound property on the DataGridViewColumn base class.

IsDataBound is set to true when AutoGenerateColumns is enabled, with one or more elements in the list, but is false is the list has zero initial elements, despite the DataPropertyName properties of the column being properly set.

Is there any way to to bind an empty list to a data grid, and allow the users to add rows to the blank list, with everything properly bound?

I've even tried adding an element to an empty list before binding, to have it auto generate and bind the columns... but as soon as the row is removed the columns disappear and the bindings are lost.

Other Implementation Details:

I am trying to bind a data source which is a custom List/Collection type that inherits from:

 - ICustomTypeDescriptor
 - IBindingList
 - ICancelAddNew
 - IList<T>
 - ICollection<T>
 - IEnumerable<T>
 - IList
 - ICollection
 - IEnumerable

The objects in the list are dynamic objects which inherit from ICustomTypeDescriptor, and map properties to values in a dictionary. The types are defined in an ObjectDefinition class that knows the available property info for the dynamic types (Property names, types, attributes, etc...) Each list has a definition assigned to it, so that every object in the list has the same definition.

I don't think this matters, because as long as there is at least one element in the list everything is properly bound, and works fine.


Solution

  • For lists, it isn't ICustomTypeDescriptor that rules, but ITypedList. Implement this at the list level, and you can supply your properties at runtime as you see fit. Because this doesn't depend on any rows, it should work even for zero rows.