DataGridView: Adding rows to an empty DGV shows no data.

The setup: I have a DataGridView that gets its data from a BindingSource. The BindingSource is given a Custom Collection that implements IBindingList. The custom collection is filled with custom dataobjects. VS2005, .net2.0.

The Problem: Rows are added to the collection programmatically. If the collection is empty and rows are added, the rows will show up on the DGV but the data for those rows will not be displayed. If the collection is saved, the window closed, and then reopened; the data will be displayed just fine.

I found this post:
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=95416&SiteID=1
But I am not sure what the user is talking about. All methods of IBindingList is implemented on my custom collection. The list changed event that is part of IBindingList is implemented where applicable (add, delete, ect…)

Thanks for any help.

Tony

[950 byte] By [TonyG] at [2008-1-9]
# 1
I created a sample app that shows the problem. Just create a new windows forms project. Run this code. Click the add button. The columns should be 0 , 1, "grrr" but they show nothing. Sorry it is kind of long.

Code Snippet

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;

namespace WindowsApplication1
{
public class Form1 : Form
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}

public Form1()
{
InitializeComponent();
}

testCollection _collection;
private void Form1_Load(object sender, EventArgs e)
{
_collection = new testCollection();
bindingSource1.DataSource = _collection;
}

private void button1_Click(object sender, EventArgs e)
{
_collection.Add(new testClass());
}

/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;

/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}

#region Windows Form Designer generated code

/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.dataGridView1 = new System.Windows.Forms.DataGridView();
this.button1 = new System.Windows.Forms.Button();
this.xDataGridViewTextBoxColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.yDataGridViewTextBoxColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.strDataGridViewTextBoxColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.bindingSource1 = new System.Windows.Forms.BindingSource(this.components);
((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.bindingSource1)).BeginInit();
this.SuspendLayout();
//
// dataGridView1
//
this.dataGridView1.AllowUserToAddRows = false;
this.dataGridView1.AllowUserToDeleteRows = false;
this.dataGridView1.AutoGenerateColumns = false;
this.dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.dataGridView1.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
this.xDataGridViewTextBoxColumn,
this.yDataGridViewTextBoxColumn,
this.strDataGridViewTextBoxColumn});
this.dataGridView1.DataSource = this.bindingSource1;
this.dataGridView1.Location = new System.Drawing.Point(12, 12);
this.dataGridView1.Name = "dataGridView1";
this.dataGridView1.Size = new System.Drawing.Size(705, 345);
this.dataGridView1.TabIndex = 0;
//
// button1
//
this.button1.Location = new System.Drawing.Point(12, 363);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(75, 23);
this.button1.TabIndex = 1;
this.button1.Text = "Add";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// xDataGridViewTextBoxColumn
//
this.xDataGridViewTextBoxColumn.DataPropertyName = "X";
this.xDataGridViewTextBoxColumn.HeaderText = "X";
this.xDataGridViewTextBoxColumn.Name = "xDataGridViewTextBoxColumn";
//
// yDataGridViewTextBoxColumn
//
this.yDataGridViewTextBoxColumn.DataPropertyName = "Y";
this.yDataGridViewTextBoxColumn.HeaderText = "Y";
this.yDataGridViewTextBoxColumn.Name = "yDataGridViewTextBoxColumn";
//
// strDataGridViewTextBoxColumn
//
this.strDataGridViewTextBoxColumn.DataPropertyName = "Str";
this.strDataGridViewTextBoxColumn.HeaderText = "Str";
this.strDataGridViewTextBoxColumn.Name = "strDataGridViewTextBoxColumn";
//
// bindingSource1
//
this.bindingSource1.DataSource = typeof(WindowsApplication1.testClass);
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(729, 452);
this.Controls.Add(this.button1);
this.Controls.Add(this.dataGridView1);
this.Name = "Form1";
this.Text = "Form1";
this.Load += new System.EventHandler(this.Form1_Load);
((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.bindingSource1)).EndInit();
this.ResumeLayout(false);

}

#endregion

private System.Windows.Forms.DataGridView dataGridView1;
private System.Windows.Forms.BindingSource bindingSource1;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.DataGridViewTextBoxColumn xDataGridViewTextBoxColumn;
private System.Windows.Forms.DataGridViewTextBoxColumn yDataGridViewTextBoxColumn;
private System.Windows.Forms.DataGridViewTextBoxColumn strDataGridViewTextBoxColumn;
}

public class testCollection : IBindingList
{
private IList<testClass> _list;

public testCollection()
{
_list = new List<testClass>();
}

#region IBindingList Members

public void AddIndex(PropertyDescriptor property)
{
throw new Exception("The method or operation is not implemented.");
}

public object AddNew()
{
return new testClass();
}

public bool AllowEdit
{
get { return true; }
}

public bool AllowNew
{
get { return true; }
}

public bool AllowRemove
{
get { return true; }
}

public void ApplySort(PropertyDescriptor property, ListSortDirection direction)
{
throw new Exception("The method or operation is not implemented.");
}

public int Find(PropertyDescriptor property, object key)
{
throw new Exception("The method or operation is not implemented.");
}

public bool IsSorted
{
get { throw new Exception("The method or operation is not implemented."); }
}

public event ListChangedEventHandler ListChanged;

public void RemoveIndex(PropertyDescriptor property)
{
throw new Exception("The method or operation is not implemented.");
}

public void RemoveSort()
{
throw new Exception("The method or operation is not implemented.");
}

public ListSortDirection SortDirection
{
get { throw new Exception("The method or operation is not implemented."); }
}

public PropertyDescriptor SortProperty
{
get { throw new Exception("The method or operation is not implemented."); }
}

public bool SupportsChangeNotification
{
get { return true; }
}

public bool SupportsSearching
{
get { return false; }
}

public bool SupportsSorting
{
get { return false; }
}

#endregion

#region IList Members

public int Add(object value)
{
_list.Add((testClass)value);
if (ListChanged != null)
ListChanged(this, new ListChangedEventArgs(ListChangedType.ItemAdded, _list.Count - 1));
return _list.Count - 1;
}

public void Clear()
{
throw new Exception("The method or operation is not implemented.");
}

public bool Contains(object value)
{
throw new Exception("The method or operation is not implemented.");
}

public int IndexOf(object value)
{
throw new Exception("The method or operation is not implemented.");
}

public void Insert(int index, object value)
{
throw new Exception("The method or operation is not implemented.");
}

public bool IsFixedSize
{
get { throw new Exception("The method or operation is not implemented."); }
}

public bool IsReadOnly
{
get { throw new Exception("The method or operation is not implemented."); }
}

public void Remove(object value)
{
throw new Exception("The method or operation is not implemented.");
}

public void RemoveAt(int index)
{
throw new Exception("The method or operation is not implemented.");
}

public object this[int index]
{
get
{
return _list[index];
}
set
{
_list[index] = (testClass)value;
}
}

#endregion

#region ICollection Members

public void CopyTo(Array array, int index)
{
throw new Exception("The method or operation is not implemented.");
}

public int Count
{
get { return _list.Count; }
}

public bool IsSynchronized
{
get { throw new Exception("The method or operation is not implemented."); }
}

public object SyncRoot
{
get { throw new Exception("The method or operation is not implemented."); }
}

#endregion

#region IEnumerable Members

public System.Collections.IEnumerator GetEnumerator()
{
return _list.GetEnumerator();
}

#endregion

}

public class testClass
{
public testClass()
{
_x = 0;
_y = 1;
_str = "grrr";
}

int _x;

public int X
{
get { return _x; }
set { _x = value; }
}
int _y;

public int Y
{
get { return _y; }
set { _y = value; }
}
string _str;

public string Str
{
get { return _str; }
set { _str = value; }
}
}
}


TonyG at 2007-10-2 > top of Msdn Tech,Windows Forms,Windows Forms Data Controls and Databinding...
# 2
Alright after some decompiling of .net DLLs using reflector and looking at bindingList<T> I think i may have found it. I am not sure if this is right or not but it seems to work.

In the add method for the custom collection, if I raise the listchanged event twice for the first row added then the data shows up.

So something like this more or less.
ListChanged(this, new ListChangedEventArgs(ListChangedType.ItemAdded, _list.Count - 1));
ListChanged(this, new ListChangedEventArgs(ListChangedType.PropertyDescriptorAdded, _list.Count - 1));
I did loop through each property that my custom objects held but that didnt seem to really matter which way I did it. It worked.

Something else that seems to work is to do the following on the binding source.
bindingSource1.ResetBinding(true);

Like I said I am not sure which way is right or if there is any gotch yas later down the road but this for the time being seems to work. If anyone has any suggestions that would be great things.

TonyG at 2007-10-2 > top of Msdn Tech,Windows Forms,Windows Forms Data Controls and Databinding...