InvalidOperationException on Databinding when removing last item in list - c#

I'm getting the following message when I try to remove the last item in a datagridview.
DataBinding cannot find a row in the list that is suitable for all bindings.
I have my binding setup as follows.
ExtendedBindingList<MyClass> bl = new ExtendedBindingList<MyClass>(GetDataFromDB());
BindingSource bs = new BindingSource();
bs.DataSource = bl;
dgv.DataSource = bs;
ExtendedBindingList is just something simple I threw together to implement sorting and filtering and some basic state persistence. dgv is the DataGridView. GetDataFromDB returns a List of MyClass.
The issue only arises when I try to remove the last item from the datagridview using:
bs.RemoveCurrent();
which works at all other times. My only hint for a solution is to remove all bindings and reapply them but this doesn't seem like an ideal solution.
EDIT
The exception only gets thrown after the BindingList successfully removes the last item in question. It get's thrown in external code so I can't tell exactly what is throwing it.
So, here I am, asking SO for some help :).
Thanks in advance,
Justin

Here is how I remove selected row from a grid:
private void btnDelete_Click(object sender, EventArgs e)
{
if (grid.CurrentRow == null) return;
var selectedItem = grid.CurrentRow.DataBoundItem as PartGroup;
if (selectedItem != null &&
UIHelper.ShowQuestion("Are you sure you want to delete selected row?") == System.Windows.Forms.DialogResult.Yes)
{
groups.Remove(selectedItem);
}
}
groups is my BindingListEx(Of T).
Hope it helps.

[Sorry, not really an answer but I feel this is valuable since no answer was given.]
I was getting the exact same situation using .NET Compact Framework 2.0. Testing traced it to the point where a NumericUpDown.DataBindings.Add() was used to bind the control to the source. After this point, using RemoveCurrent() would produce the error if the item was the last one in the source. Prior to that binding (or if it was skipped), the error would never appear.
Other controls were bound to this same source -- TextBox and ComboBox -- but they did not cause this behavior. Only the NumericUpDown control.

Related

ComboBox showing System.Data.DataRowView after changing selection

I have been looking at all the other questions similar to this one and they just don't seem to help me with my particular problem.
I am using a Combobox with the following properties:
The purpose of the Combobox is simple, it is taking all the values of an unique column in a table, and present them as options. The column's name is "nim".
Upon initialization, the combobox loaded just fine:
The problem occurs after I changed the selected item to the 2nd one in the list, and tried changing it again:
When I tried selecting System.Data.DataRowView, this error appeared:
I have been playing around with the code to no avails. I didn't write any code concerning the combobox. I just assign the DataSource, DisplayMember, and ValueMember from the properties window manually.
The only code concerning combobox is these:
private void comboNIM_SelectedIndexChanged(object sender, EventArgs e)
{
//selectedNIM = ((DataRowView)comboNIM.SelectedItem).Row["nim"] as String;
selectedNIM = comboNIM.SelectedValue.ToString();
}
Any help will be really appreciated! Thank you!
So..., I have found a solution for this particular problem.
I deleted the ComboBox, and then created a new one. Then I just assign the properties programmatically.
cb.DisplayMember = 'nim';
cb.ValueMember = 'nim';
cb.DataSource = mahasiswaBindingSource;
Apparently, leaving the properties window unedited solved the problem!

IndexOutOfRangeException error when DataGridView is clicked

I have been struggling with this issue for some hours.
This is what happens:
When my form loads, I have a DataGridView with an empty List<Entity> as datasource.
DataGridView.Datasource = null;
DataGridView.Datasource = entity_list;
First, I set it to null so as to update the DataGridView.
Then, I can add entities to that list, so that piece of code will be executed everytime I add one.
The problem I get is that after adding one entity to the list and updating the DataSource, I got an IndexOutOfRangeException when I clicked the DataGridView. It´s pretty wierd.
The problem appears because I can add entities to that List, and for some reason, if the DataSource is an empty List, this exception shows up when you try to add one entity to it.
So, the solution I used, is to asked before doing the list binding, if that list has at least 1 entity.
DataGridView.DataSource = null;
if (entity_list.Count() > 0)
{
DataGridView.DataSource = entity_list;
}
And thats it! Solved! I read that using BindingLists can be a way to solve that to, but if you are using List like me, I hope this can help you out!

EndEdit on BindingSource updates DataTable, but rowstate still unchanged

I have a bindingsource which has a datasource which is a datatable.
All the winforms controls has added databindings to the bindingsource
I do a value change in the GUI (writes to the controls' .text property)
then on Save i do following
bsSending.EndEdit();
((DataRowView)this.bsSending.Current).Row) now contains the new values, but the RowState is still unchanged. How can this be possible? I haven't any calls to AcceptChanges() before I make the value changes in the GUI
UPDATE:
Don't know why, but it seems that calling the specific row's EndEdit does the trick. The row's parent is a datatable and the table's dataset is the datasource of the bsSending Datasource.
Calling bsSending.EndEdit() only updates the values but doesn't update the rowstate.
I have surfed the .net for similiar problems and they indicate that when calling AcceptChanges() on the dataset BEFORE binding data, then you may get this error (values updated to dataset but rowstate remains unchanged). I haven't seen any solutions to the problem, though, so I keep my workaround solution
I know it's old post.
It can be solved by calling DataRowView.EndEdit directly, but in my case I found the exact reason:
I accidentally bound two properties of one control to different columns.
(In my case I simultaneously bound Devexpress' TextEdit control - EditValue and Text properties to different columns of the underlaying table).
Maybe it will help someone even in 2016+, because it was nasty bug to catch.
I have a similar issue. I have a grid on the first tab page and textboxes on the second tab page, all binded to the same binding source.
I change the row content, the content get changed in the grid but the row start is Unchanged.
My code was:
DataRow dataRow = ((DataRowView)bindingSource1.Current).Row;
if(dataRow.RowState != DataRowState.Modified)
I expected to have a Modified rowState.
The missing code was:
bindingSource1.EndEdit();
Entire solution here:
private void tabControl1_SelectedIndexChanged(object sender, EventArgs e)
{
if (tabControl1.SelectedIndex == 0)
{
bindingSource1.EndEdit();
DataRow dataRow = ((DataRowView)bindingSource1.Current).Row;
if(dataRow.RowState != DataRowState.Modified)
{
return;
}
DialogResult userOption = MessageBox.Show("Save?", "Confirm", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (userOption == System.Windows.Forms.DialogResult.Yes)
{
Save();
}
}
}
My solution:
I have run into the similar situation in one form and I realized that problem was in binding made to labels ToolTip property. First I realized, that when I changed value for null from null to some string, the problem disappears, but after some other changes made to the project, the problem appeared again. When I deleted binding to the ToolTip property, problem disappeared again. Still I do not know if for ever.
#Jan Strnad 's answer enlightened me and helped me fix my issue.
Problem: I was using a binding source in win forms. When binding the controls in the form, I miss clicked and bound a field to the form's Text property in (DataBindings). The same bindingsource field was bound (correctly) to a combobox. Because of this double binding on the field, the rowstate never changed from Unmodified.
Fix: when rows don't update and you use a binding source, first check that the binds are correctly put in place.
Yes, I have the same experience. I am using Visual Studio 2010 and .NET Framework v.4.0. I am working with DataGridView control which is bound to a DataTable.
If the user tries to close the form while the cell value is still in edit mode, I want DataGrid to end the edit mode and ask the user whether he wants to save or lose the changes.
This is the code which works for me:
if (dgv.IsCurrentCellInEditMode)
{
dgv.EndEdit();
updatedData.Rows[dgv.CurrentCell.RowIndex].EndEdit();
}
if (updatedData.GetChanges() != null && updatedData.GetChanges().Rows.Count > 0)
{
// if there are changes, update the dataset
}
I want to point out that I needed to call both - EndEdit() on DataGridView to let it end the editing. Then call EndEdit() on the DataTable to mark the row 'modified'.
To commit row changes programmatically, call the form's Validate method. If your data source is a BindingSource, you can also callBindingSource.EndEdit.
see
IsCurrentRowDirty

DataBind or DataBound

I thought I had a simple task; add "Select..." to several dropdown lists.
However I am not getting the results I want and I am getting more and more confused if I should be using the dataBound or dataBinding event in my Gridview edit mode.
My code is pretty simple;
protected void ActivityList_DataBinding (object sender, System.EventArgs e)
{
DropDownList ddl2 = (DropDownList)(sender);
var act = Eval("myactivity").ToString();
if (act != "") { ddl2.SelectedValue = act; }
ddl2.Items.Insert(0, new ListItem("Select..", "-1"));
}
This checks if a value has already been selected, and would hopefully jump to the selection if it has been, still adding a Select item to the list.
Using the dataBound event works in the sense it addes my Select, but does not go to the selected value if there is one. Also it is creating odd behavior, jumping to the top of my page upon selection, rather than staying on the row I am editing.
Using dataBinding does not show my added items at all.
All advice welcome!
Alex (Lost in CodeLand)
Set your AppendDataBoundItems=True in your DDL. If you are calling the databind method in code you will want to clear the items and readd the new listitem before databinding.

How to remove selected items from ListBox when a DataSource is assigned to it in C#?

How to remove selected items from ListBox when a datasource is assigned to it in C#?
When trying to remove, got error
"Items collection cannot be modified when the DataSource property is set."
But when i try to remove item from datasource (datatable) ,
it thorws error as "datarow is not in current row collection".
Find that item in the DataSource object and remove it, then re-bind the ListBox.
EDIT:
Here's how you delete from a DataTable as your DataSource, regardless of the .NET version.
DataRowView rowView = listBox.SelectedItem as DataRowView;
if (null == rowView)
{
return;
}
dt.Rows.Remove(rowView.Row);
I haven't tried with anything other than WinForms DataGridViews, but I highly recommend BindingListView, which is both faster than DataTables/Views and allows you to bind generic List<T>s as your DataSource.
Alternatively, use a list that implements IBindingList or inherits from BindingList. When objects are added or removed from a Binding List, any controls bound to it are automatically notified of the change and will update themselves accordingly. If you are using BindingList and your class also implements INotifyProperty changed, Any changes to class properties will also be updated automatically in the databinding control. For example, if a column in a datagrid(view) is bound to a property, "Name", and you change "Name" in the datasource, the datagrid will automatically update. If you add a new item to the datasource, the datagrid will update automatically. Binding List also supports notification in the other direction. If a user edits the "Name" field ina datagrid, the bound object will be updated automatically. Going off topic slightly, if you go a little further and impliment "SupportsSortingCore" and the associated methods in BindingList, you can add automatic sorting to your data. Clicking on a columnm header will automatically sort the list and display the header sort direction arrow.
If the ListBox has a datasource assigned, you must remove items from the datasource and then rebind the ListBox
You need to modify the data source rather than the Items collection of the control. Depending on what kind of data source you are binding to, there are going to be different things you have to do so that your UI updates.
The best way is find a collection that fits your needs and implements IBindingList or IBindingListView. Those two interfaces implement even handlers that listen for a CollectionChanged event and update your UI accordingly.
If your collection doesn't support those interfaces, you're going to have to re-bind your data source every time somebody adds/removes an item.
when you get the message "Items collection cannot be modified when the DataSource property is set."
setting the datasource to something else, empty list or null does not help when
the code initializecomponent is not completed.
to avoid that error, one must do the change of datasource or the item list during or after form load.
I know it does not seem to make sense. Hoever, the visual studio designer will generate code in the form designer.cs or vb that will add items to the listbox if any code that changes the items is found before end of initialize components
While Chris Doggett posted a valid solution, I ran into problems while using it. By using that method it was not allowing a subsequent GetChanges(DataRowState.Deleted) to work properly.
To better solve my problem, I only had to change a single line - the last line.
DataRowView rowView = listBox.SelectedItem as DataRowView;
if (null == rowView)
{
return;
}
rowView.Row.Delete();
This allowed my GetChanges call to work properly.
This worked for me
DataTable temp = (DataTable)lstBlocks.DataSource;
temp.Rows.RemoveAt(position);
its vary simple , assign a new blank value to listbox
eg..
Dim ABC As New List(Of String)()
ListBox1.DataSource = ABC
ListBox implementation is bugged, you need to create a new data source instance for the component for it to recognize a change.
Eg:
ActivitiesList.DataSource = _activities;
_activities = new List<Activity>(_activities);
_activities.Remove((Activity)ActivitiesList.SelectedItem);
ActivitiesList.DataSource = _activities;

Categories