I have a DataGridView that is bound to a BindingSource at design time. Also
at design time the BindingSource has its DataSource bound to one of my
classes. This class is simply a wrapper that derives from generic list but
sets the type of the list item (i.e., public class MyClass : List<MyType> )
This whole thing was working beautifully and I could add new items to the
bindingsource at any location and the datagridview would update. In the
initial view, the grid was empty except for the empty "new row" entry at the
bottom.
I don't know what changed, but now when I add the first item (which happens
through a menu interaction) I wind up with my expected new row at the top and
the standard "new row" entry at the bottom, AND an empty row in the middle.
The timing of the visibility of the phantom empty row turns out to be an
artifact of when things get painted.
What I know is that: After InitialIzeComponent Rows.Count in the view and
the BindingSource are 0, and if I break on the first user interaction,
Rows.Count is ONE in both. I'm expecting that for the View, but not the
BindingSOurce. Also, MyType's empty constructor is called after sometime
after my form's constructor from "external code".
So, not surprisingly, when I add my first item and the view is updated, it
correctly displays both my added row and the phantom empty row in addition to
the bottome "new row" entry.
The phantom row isn't supposed to be there, and I don't think that it was
earlier in my development process.
I changed the designer so that the DataGridView had AllowUserToAddRows was
set to FALSE but I left AddNew in the BindingSource TRUE. At the break on
first user interaction, Rows.Count was ZERO for both (expected).
I then added a Paing event handler for the DataGridView and on the first
paint I set AllowUserToAddRows to TRUE. Now, at the first break, Rows.Count
for the View was ONE (expected) and Rows.Count for the BindingSource was ZERO
(expected).
Now, when I do the first add or insert to the BindingSource I wind up with
two rows in the View, the one I added and the "new row" entry. The phantom
row is gone.
I don't know what property I changed that made this incorrect behaviour
happen, but I'm sure that I shouldn't have to play with AllowUserToAddRows in
a Paint event to make things work.
Thx
Marc
Linda Liu[MSFT] - 06 Nov 2007 08:14 GMT
Hi Marc,
I performed a test based on your description. I didn't reproduce the
problem of a phantom empty row appearing in the DataGridView when a new
item is added into the data source.
In my test, I set the AllowUserToAddRows property of the DataGridView to
true and call the AddNew method of the BindingSource to add a new item into
the data source. After I call the BindingSource.AddNew method for the first
time, the rows count in the BindingSource is 1 and that in the DataGridView
is 2. The added row appears at the top of the DataGridView and the "new
row" entry is at the bottom.
The following is the code in my test. It requires a DataGridView and a
Button are added onto the Form1.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
List<Person> lists = new List<Person>();
BindingSource bs = new BindingSource();
private void Form1_Load(object sender, EventArgs e)
{
this.dataGridView1.AllowUserToAddRows = true;
bs.DataSource = lists;
this.dataGridView1.DataSource = bs;
Console.WriteLine("load-dgv row count:" +
this.dataGridView1.Rows.Count.ToString());
Console.WriteLine("load-binding source:" + bs.Count.ToString());
}
private void button1_Click(object sender, EventArgs e)
{
bs.AddNew();
Console.WriteLine("datagridview row count:"
+this.dataGridView1.Rows.Count.ToString());
Console.WriteLine("binding source:" + bs.Count.ToString());
}
class Person
{
private int id;
private string name;
public int ID
{
get { return id; }
set { id = value; }
}
public string Name
{
get { return name; }
set { name = value; }
}
}
}
You may test the above sample code on your side to see if you get the same
result. You may also have a try removing the existing DataGridView on your
form and adding a new one to see if the problem still exists.
Hope this helps.
Sincerely,
Linda Liu
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.
Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
MarcG - 06 Nov 2007 16:51 GMT
Linda,
Yes your example works (of course), but ...
In my case, I'm binding the view to the BindingSource and the BindingSource
to the datasource at design time. Also, the problem has nothing to do with
how the Add is done since the problem (mystery row in the bindingsource rows
collection) already exists by the time of the first user interaction.
Interestingly, I went back to my code (that has AllowUserToAddRows = false
in the designer) and moved the code that sets it to true from the first paint
event to the form load event. In this case, the problem persists. I.e.,
changing the setting in Paing fixes it, but changing it in Load does not.
I did go back and deleted my datagridview and added and reqired a new one.
This did not fix the problem.
Marc
> Hi Marc,
>
[quoted text clipped - 86 lines]
>
> This posting is provided "AS IS" with no warranties, and confers no rights.
Linda Liu[MSFT] - 07 Nov 2007 10:53 GMT
Hi Marc,
Thank you for your quick response!
I think it would be better for me to have a repro project to solve the
problem.
If possible, could you please create a sample project that could just
reproduce the problem and send it to me?
To get my actual email address, remove 'online' from my displayed email
address.
Sincerely,
Linda Liu
Microsoft Online Community Support
Linda Liu[MSFT] - 08 Nov 2007 09:09 GMT
Hi Marc,
Thank you for your sample project and detailed explanation! I did see the
problem on my side and understand your problem.
The reason of the problem is that when we select the "new row" row in the
DataGridView, the DataGridView is actually in the "add" mode(If we call the
BindingSource.AddNew method at this time, we will get an exception
"Operation is not valid due to the current state of the object."), and the
DataGridView adds a new row into the underlying data source internally.
This is why you see the item count in the BindingSource has become 1 when
you right click in the "new row" row header and the context menu pops up.
If we add our own new row into the BindingSource at this time, there will
be two rows added into the BindingSource at last.
To solve the problem, I suggest that you set the AllowUserToAddRows
property of the DataGridView to false and set the ContextMenuStrip property
of the DataGridView to the rowContextMenu. You need to change the logic in
your code to make it possible to add a new row into the BindingSource when
there's no rows in the BindingSource currently.
Hope I make some clarifications.
If you have anything unclear, please feel free to let me know.
Sincerely,
Linda Liu
Microsoft Online Community Support
Linda Liu[MSFT] - 09 Nov 2007 09:57 GMT
Hi Marc,
Thank you for your prompt reply!
> I can see a method to cancel edit, but not to cancel add
In fact, we can cancel an add operation. To do this, just call the
BindingSource.CancelEdit method. So another workaround of the problem is to
call the BindingSource.CancelEdit method from the handler of the
DataGridView's RowHeaderMouseClick event. For example:
private void scheduleView_RowHeaderMouseClick(object sender,
DataGridViewCellMouseEventArgs e)
{
DataGridView gv = sender as DataGridView;
if (e.Button == MouseButtons.Right)
{
// call the CancelEdit method to cancel the add operation
fired by the DataGridView internally
this.taskScheduleBindingSource.CancelEdit();
¡
}
}
> But I'd love to know what configuration I had that worked before
Is it possible that you used a different kind of data source before?
Sincerely,
Linda Liu
Microsoft Online Community Support