Windows Develop Bookmark and Share   
 index > Windows Forms Data Controls and Databinding > BindingSource's AddNew fired automatically if no object in collection
 

BindingSource's AddNew fired automatically if no object in collection

I have a form holding a list of data objects for the user to browse and select to edit.  The data objects come from a CollectionBase-derived object that implements IBindingList (in fact, it's BusinessCollectionBase of CSLA .NET Framework).  This collection is bound to a BindingSource, then the BindingSource is bound to a BindingNavigator and a DataGridView.

When this form is loaded, the collection class' static method will read the data from the database and return a collection instance.  If some data objects are loaded into the collection, everything is ok and the BindingSource's AddingNew event will not be fired automatically.  If no data object is loaded into the collection, then the BindingSource's AddingNew event will be fired automatically.  And then my code will load a second form to edit a new data object.

Then I just simply close the second form without saving the new data object.  The execution returns to the list form, and re-bind the BindingSource with a new collection returned from the collection's static method.  Since no data object is added, the collection is still emtpy.  And an exception is thrown: System.InvalidOperationException: Operation is not valid because it results in a reentrant call to the SetCurrentCellAddressCore function.

Why is it ok when the collection is not empty but causing an exception when the collection is empty?  Maybe my re-binding is wrong?  BTW, at design time, I bind the BindingSource with the MyCollectionClass type.

My code snippet is attached below.



private void MyListForm_Load(object sender, EventArgs e)
{
    BindData();
}

private void myBindingSource_AddingNew(object sender, AddingNewEventArgs e)
{
    // load edit form to edit a new data object

    RefreshBinding();
}

private void BindData()
{
    myCollection = MyCollectionClass.GetData();  // returns a MyCollectionClass instance with 0 or more data objects, so every time this is a new instance
    myBindingSource.DataSource = myCollection;   // exception occurs here after returning from edit form with an emtpy collection
}

private void RefreshBinding()
{
    BindData();
    //myBindingSource.ResetBindings(false);  // should I call this?
}

 


Thanks!

blackpuppy  Wednesday, June 29, 2005 8:01 AM

You may be able to work around this by setting AllowUserToAddRows to false before calling RefreshBindings() and then set it to true after you've called RefreshBindings().

In general, I'd recommend against re-binding in AddingNew.  AddNew will create an instance of your type (if possible) and add it to your list.  The way this was architected to work was that if your list was empty, AddNew (AddingNew) would get called.  In AddingNew you should create a new instance of your type, possibly set default values, and then set e.NewObject to the new instance.  In your case, you're re-binding in AddingNew and not creating a new instance (which BindingSource will then do for you) which may cause additional problems.

The design pattern is:

   Bind you Grid to the BindingSource
   Bind your DataSource (list) to the BindingSource
   If you DataSource is Empty, AddNew will get called (which fires AddingNew)
      In AddingNew set e.NewObject to a new instance of your Type
      BindingSource will then add this new instance to the DataSource (list)


Joe Stegman
The Windows Forms Team
Microsoft Corp.

This posting is provided "AS IS" with no warranties, and confers no rights.

Joe Stegman  Thursday, June 30, 2005 2:31 AM

You may be able to work around this by setting AllowUserToAddRows to false before calling RefreshBindings() and then set it to true after you've called RefreshBindings().

In general, I'd recommend against re-binding in AddingNew.  AddNew will create an instance of your type (if possible) and add it to your list.  The way this was architected to work was that if your list was empty, AddNew (AddingNew) would get called.  In AddingNew you should create a new instance of your type, possibly set default values, and then set e.NewObject to the new instance.  In your case, you're re-binding in AddingNew and not creating a new instance (which BindingSource will then do for you) which may cause additional problems.

The design pattern is:

   Bind you Grid to the BindingSource
   Bind your DataSource (list) to the BindingSource
   If you DataSource is Empty, AddNew will get called (which fires AddingNew)
      In AddingNew set e.NewObject to a new instance of your Type
      BindingSource will then add this new instance to the DataSource (list)


Joe Stegman
The Windows Forms Team
Microsoft Corp.

This posting is provided "AS IS" with no warranties, and confers no rights.

Joe Stegman  Thursday, June 30, 2005 2:31 AM

   I am receiving the same issue, but I am not using binding.  Here is my scenario; I have a datagridview that accepts user input.  On the CellEndEdit, the underlying dataset (unbound) is updated.  At this point an event is raised to update the UI.  This process clears the data grid and reloads.  The dgv.Rows.Clear(), throws the exception.  Now this does not happen on all columns, just the combo and checkbox columns.

 

Any advice would be greatly appreciated,

Darell F. Butch Jr.

Darell F. Butch Jr_  Friday, July 22, 2005 3:46 PM
I'm getting a similar problem to the above.

I'm putting a combobox into a cell (which starts off as a text cell) when cell receives focus, and changing the cell back to a text cell again (with the value selected) when it loses focus.

It all works fine until the rowindex and columnindex are both 2 - I haven't tried it with other values, so it may be that when they're equal, the problem arises.

The exception message is "Operation is not valid because it results in a reentrant call to the SetCurrentCellAddressCore".

Any help would be greatly appreciated.
RichardC_UK  Friday, March 03, 2006 4:37 PM
(a little later)

The problem arises when the rowindex and columnindex are equal. I've only tested this on values of 2 and 3, tho.
RichardC_UK  Friday, March 03, 2006 4:56 PM

I have a very similar problem.
The DataGridView consists of only two ComboBoxColumns
As the form loads I bind the DataGridView.DataSource to a DataTable.
Next the user clicks the "Add" button and I set as it follows:

DataGridView.AllowUserToAddRows = true;
DataGridView.EditMode = System.Windows.Forms.
DataGridViewEditMode.EditOnEnter;

If news values are selected, the changes are saved and I set the DataGridView state back to normal:

DataGridView.AllowUserToAddRows = false;
DataGridView.EditMode = System.Windows.Forms.DataGridViewEditMode.EditProgrammactically;

If no new values are selected, no action is taken and I set the DataGridView state back to normal and here is where the problem happens:

DataGridView.AllowUserToAddRows = false;
generates the exception in discussion: "Operation is not valid because it results in a reentrant call to the SetCurrentCellAddressCore".

Any help? Please? =(

Edmaneiro  Monday, August 14, 2006 7:52 PM
Hi, Darell: Have you got the answer yet? I am having the same problem. If you have the answer, please kindly share it with us. Thanks in advance :)
Jin17  Thursday, September 21, 2006 9:06 PM

No, I did not get an actual answer. I got the work around, which was posted above. We are currently using another control and have not transitioned back to the DataGridView. Also, we have upgraded to latest version which I believe has fixed the problem, but have not tried it. If you would like me to do that, I could and give you the results.

Darell F. Butch Jr_  Friday, September 22, 2006 12:04 PM

We had a similar problem where once the grid was updated we wanted to refresh the grid. I was getting the error. It appears thatatt he point that I want to refresh the grid (in the RowEnter) thehandle on the grid is on a different thread.

Instead I had to call the function using a

Dim refreshDelegate As New MethodInvoker(AddressOf RefreshGrid)

refreshDelegate.BeginInvoke(Nothing, Nothing)

and in my RefreshGrid function I had to test to see if the InvokeRequired was false before running the code to refresh the data.

If InputOutputGrid.Grid.InvokeRequired Then

Dim callBack As New SetGridCallBack(AddressOf RefreshGrid)

Me.Invoke(callBack, Nothing)

Else

........ code to update the grid.

Hope this helps

CodeBash  Wednesday, December 27, 2006 2:17 PM
Have you found an work around for this?
viperjason  Thursday, February 22, 2007 1:30 AM
RichardC_UK wrote:
I'm getting a similar problem to the above.

I'm putting a combobox into a cell (which starts off as a text cell) when cell receives focus, and changing the cell back to a text cell again (with the value selected) when it loses focus.

It all works fine until the rowindex and columnindex are both 2 - I haven't tried it with other values, so it may be that when they're equal, the problem arises.

The exception message is "Operation is not valid because it results in a reentrant call to the SetCurrentCellAddressCore".

Any help would be greatly appreciated.


Got it fixed, but it still causes a slight annoyance. The current cell changes on cell leave. But sinces its for that only cell, I can live with it.

class FixReEntrantDataGridView : DataGridView
{
private bool reEntrent = false;
protected override bool SetCurrentCellAddressCore(int columnIndex, int rowIndex, bool setAnchorCellAddress, bool validateCurrentCell, bool throughMouseClick)
{
bool rv = true;
if (!reEntrent)
{
reEntrent = true;
rv = base.SetCurrentCellAddressCore(columnIndex, rowIndex, setAnchorCellAddress, validateCurrentCell, throughMouseClick);
reEntrent = false;
}
return rv;
}
}
viperjason  Thursday, February 22, 2007 1:53 AM
Better solution that removes the annoyance, but its not good coding practice. At least it works though.
class FixReEntrantDataGridView : DataGridView
{
public bool reEntrent = false;
protected override bool SetCurrentCellAddressCore(int columnIndex, int rowIndex, bool setAnchorCellAddress, bool validateCurrentCell, bool throughMouseClick)
{
bool rv = true;
if (!reEntrent)
{
rv = base.SetCurrentCellAddressCore(columnIndex, rowIndex, setAnchorCellAddress, validateCurrentCell, throughMouseClick);
}
return rv;
}

}

and then when changing the cell from combo box to text box and visa-versa.
this.myDataGrid.reEntrent = true;
this.myDataGrid.Rows[e.RowIndex].Cells[e.ColumnIndex] = dgvt;
this.myDataGrid.reEntrent = false;

It works and it still protects the SetCurrentCellAddressCore from getting called at the wrong times.
viperjason  Thursday, February 22, 2007 6:14 PM

Thanks for posting the code bellow. It help me to solve my problem:

class FixReEntrantDataGridView : DataGridView
{
private bool reEntrent = false;
protected override bool SetCurrentCellAddressCore(int columnIndex, int rowIndex, bool setAnchorCellAddress, bool validateCurrentCell, bool throughMouseClick)
{
bool rv = true;
if (!reEntrent)
{
reEntrent = true;
rv = base.SetCurrentCellAddressCore(columnIndex, rowIndex, setAnchorCellAddress, validateCurrentCell, throughMouseClick);
reEntrent = false;
}
return rv;
}
}

albert tan  Saturday, June 30, 2007 5:29 PM
I found that this error is not reproduced if you set to MultiSelect Property to False


Apolizoi  Friday, July 13, 2007 10:34 AM

I finally received an answer to my bug submission about this: it appears that it is 'by design':

(you need to sign in to view the answer)

https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=119366&wa=wsignin1.0

So that's that Smile

RichardC_UK  Friday, July 13, 2007 12:55 PM

Thanks for this tip. However I can't figure out how to implement it. When FixReEntrantDataGridView is triggered. Can you help a litle more?

Thanks

JJLobo

João José Lobo  Friday, November 30, 2007 1:42 PM

Hi,

I am working on a windows application and had faced the same problem. I have no dropdowns in my grid, but had to bind the dropdown outside the grid on selection of a row. This dropdown has a dual role of searching and displaying ( i mean i can select a value from the drop down and on selection change it should search for the relevant values and reload my grid as well as on selection of a row i have to bind the value to the dropdown).

The work around was toreplace the DropdownList_SelectedIndexChnaged to DropdownList_SelectionChangeCommited.

Hope this will help you Smile

Regards,

Candida

Candida G  Tuesday, August 19, 2008 4:25 AM
Thanks for the tip: I used a workaround, but I'll dig up the code and see if it works now Smile
RichardC_UK  Thursday, August 21, 2008 11:29 AM

You can use google to search for other answers

Custom Search

More Threads

• DataSource <--> Form data traveling events
• Building a custom cell/column for the DataGridView
• Any recommendations on troubleshooting a concurrency error?
• Setting default value for null in datacolumn and datagrid
• Speeding up populating a ListView
• How to merge column in DataGridView ?
• Need a simple example of a 3 tier application
• empty DataGridView
• how to controll the cell focus in datagrid row ?
• How to know if DataBoundItem has a correct value?