Items in WinForms ComboBox not updating when DataSource values change - c#

I have a ComboBox bound to a List via a DataSource. For some reason, when the datasource items change, the items in the combo box don't seem to automatically update. I can see in the debugger the datasource contains the correct items.
There are lots of answers on StackOverflow about this, but most are either unanswered, don't work for me, or require changing from using Lists to BindingLists which I cannot do this instance due to the volume of code which uses methods BindingLists don't have.
Surely there must be a simple way of just telling the ComboBox to refresh it's items? I can't believe this doesn't exist. I already have an event which fires when the Combo needs to be updated, but my code to update the values has no effect.
Combo declaration:
this.devicePortCombo.DataBindings.Add(
new System.Windows.Forms.Binding("SelectedValue",
this.deviceManagementModelBindingSource, "SelectedDevice", true,
DataSourceUpdateMode.OnPropertyChanged));
this.devicePortCombo.DataSource = this.availableDevicesBindingSource;
Code to update the combobox:
private void Instance_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "AvailableDevices")
{
// Rebind dropdown when available device list changes.
this.Invoke((MethodInvoker)delegate
{
devicePortCombo.DataSource = AvailableDevicesList;
devicePortCombo.DataBindings[0].ReadValue();
devicePortCombo.Refresh();
});
}
}

You are not binding the DataGridview's DataSource to same BindingSource object in your case this.availableDevicesBindingSource which bound first time. but later you are binding to different object AvailableDevicesList. again you are using another binding source for SelectedValue i.e this.deviceManagementModelBindingSource.
use one BindingSource only, may solve your issue

Related

Set datasource of combobox in devexpress in gridview c#

I am trying to create a gridview with list as you can see
I add the item of the list using this code :
private void frmDocument_Load(object sender, EventArgs e)
{
gridControlDocument.DataSource = new BindingList<Document>(_documentRepository.Get().ToList()) { AllowNew = true };
DisciplineList.Items.Add("ali");
}
but i need to get data from the database ,but the DisciplineList doesn't have the datasource property .
The ComboBoxEdit control is not meant to be bound to a data source. You would need to either loop through your DisciplineList collection and add each item manually, or use the LookUpEdit control, which does offer a data source property.
In your case, you can add a RepsositoryItemLookUpEdit to the GridControl (See: Assigning Editors for In-Place Editing) and set its DataSource property to your collection. Additionally, set the ValueMember and DisplayMember properties to a property within the Discipline class.

DataGridView not updateing when I'm changing datasource

I have DataGridView and DataSource is List. When I'm changing elements property in that List in gridview it is shown previous. When I click on row it changes values. I'm updating list with BackgroundWorker. How update DataGridView at the same time?
You will have to use ObservableCollection combined with INotifyPropertyChanged as ObservableCollection notifies only when items are added or removed but not when they are changed.
ObservableCollection Class
How to Listen to Property Changes of Items of an ObservableCollection
There is also one more similar question on SO that might help you.
modified excerpt from msdn
private void RefreshGrid(object dataSource)
{
yourGridName.Invoke((Action)delegate
{
var myCurrencyManager = (CurrencyManager)yourGridName.BindingContext[dataSource];
myCurrencyManager.Refresh();
});
}
Call this method whenever your background worker updates the dataSource.

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.

Sync a WinForm with DatagridView

I have a Form with a DataGridView which DataSource is a BindingSource to a table. This view will have a single row selection and a button to delete, edit the current selected row in a popup Form and a insert button that will use the same Form as well.
My question is how can I sync the pop Form with the current row?
I tryied to use the RowStateChanged event to get and store the current selected Row to be used in the Form but I coudnt. After the event I get the row that was selected before.
Other thing I dont understand yet in C# how to have a single recordSet and know wich is the current record even if its a new being inserted in a way that once in the Form all data being entered will show up at the same time in the DataGridView.
You don't have to sync the form with the current row. That's what a BindingSource is for.
When you do simple binding to a BindingSource, then every time its current item changes, the bound controls get updated, and every time the values in the bound controls change, the underlying values in the bound item get updated. When you do complex binding (i.e. the bound control displays the BindingSource's list, not just the current item), changing Position on the BindingSource will also change the current position in the bound control, and vice versa. So in this case, you want to bind the controls on your second form using simple binding, and the DataGridView on your first using complex binding.
The only unusual thing you need to do is make sure that both forms are using the same BindingSource. When you do that, clicking on a new row in the DataGridView updates the Position on the BindingSource, and the BindingSource pushes the values from the current bound item out to all of the simply-bound controls that are bound to it.
This is easily accomplished. Assuming that Form1 is the form with the DataGridView, and Form2 is the one with the simply-bound controls, do this:
In Form1:
private BindingSource Source = new BindingSource();
Form1_Load(object sender, EventArgs e)
{
// set Source's DataSource to your DataTable here.
mainDataGridView.DataSource = source;
// create DataGridView columns and their bindings here.
Form2 f2 = new Form2();
f2.TopMost = true;
f2.Source = Source;
f2.Show();
}
In Form2:
public BindingSource Source { get; set; }
public void Form2_Load(object sender, EventArgs e)
{
idTextBox.DataBindings.Add("Text", Source, "id");
descriptionTextBox.DataBindings.Add("Text", Source, "description")
}
You can easily keep it in sync, but not using BindingSource.
Windows Forms data binding is built on top of a few interfaces the most important are:
IList and IBindingList. The first one is just responsible for providing access to elements by their index in the list(to make it simple) the second one actually is more complicated.
IBindingList - (which is implemented by BindingSource) has methods to support:
change notification
adding new "empty" element
sorting
searching
The one that is important for you is of course change notification. Unfortunately BindingSource doesn't implement that bit of code. You may do 2 things here - either implement your version of BindingSource with change notification or try to mess with DGV and textboxes/comboboxes events to update the data.
Personally I've done the first one(I can share the code I have).
"Other thing I dont understand yet in C# how to have a single recordSet and know wich is the current record even if its a new being inserted in a way that once in the Form all data being entered will show up at the same time in the DataGridView."
Every form has a BindingContext object that keeps CurrencyManagers - one for each DataSource. That way every control bound to the same data source knows which record is current. Actually what BindingNavigator does is messing with the apropriate CurrencyManager and calling its methods. (I have no idea why it requires BindingSource instead of in the minimum IList or for full functionality IBindingList)

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