One DataSource for multiple controls - c#

I have two ListBox in my winforms application, I assigne a datasource for both of them as follow:
private void MakeMeasurementUnits()
{
var units = new List<MeasurementUnit>
{
new MeasurementUnit {Name = "Current", SiUnit = "A"},
new MeasurementUnit {Name = "Voltage", SiUnit = "V"},
new MeasurementUnit {Name = "Time", SiUnit = "s"},
new MeasurementUnit {Name = "Temprature", SiUnit = "°C"}
};
lbxXunit.DataSource = units;
lbxYunit.DataSource = units;
}
The strange thing is (or maybe because it is my first time!!), in the form when I click on items of one of these lisboxes, the same item in the second listbox gets selected as well. Is this a default behaviour? how to prevent this? If this is default behaviour, what is useful about it?
I found the quick remedy to be making two different datasources (same thing with another name)

The listbox seems to cache the binding source. This is default behavior. If you want to avoid this, the easy way is to create a copy of the list to bind to the second data source:
lbxXunit.DataSource = units;
lbxYunit.DataSource = units.ToList();
This is useful when you have multiple views of the same data and want to synchronize the selection of these items.

Yes, this is normal behaviour. It happens because the ListView control uses a BindingSource object to track the currently selected item. (A List has no way to track a selected item without a BindingSource.)
By default, a DataSource in a WinForms control uses a BindingSource created for it by the WinForms system itself.
You can read more about the BindingSource at:
http://msdn.microsoft.com/en-us/library/system.windows.forms.bindingsource.aspx
There is an article here which might help too:
http://blogs.msdn.com/b/bethmassi/archive/2007/09/19/binding-multiple-comboboxes-to-the-same-datasource.aspx

The behavior you have noted is the default/correct behavior for winforms controls. You can achieve what you are after by setting a new BindingContext for your second listbox control without creating a copy of your data source.
BindingContext

This is correct behaviour. The datasource management in WindowsForms keeps track of the selected item on control and manipulates binded data too.
The resolution you've found already: is assign 2 different data sources objects to these controls.

Related

Winform (.Net) databind and selection problem

It was a looooooong time since I did a winform desktop application in .Net and I wanted to do some selections based on listboxes. The problem is that any item I select in a listbox also changes the selection of the other listboxes bound to the same data. I tried to find people who have had the same problem but couldn't find any so I guess I'm doing something fundamentally wrong. Anyone have any hints? See below for the basic code.
Class for handling data (to which I later use as DataSource in listboxes).
public class Registry
{
public ICollection<Data.Vertice> Vertices { get; set; } = new List<Data.Vertice>();
}
How I set the data source to a listbox
listBox1.DataSource = null;
listBox1.DataSource = _registry.Vertices;
listBox1.DisplayMember = "Title";
Reza Aghai Solved the problem by finding a a post which I had missed in my search.
Basically a single BindingManagerBase is created and reused if you use the same DataSource. This can be solved by creating a new DataSource by for example doing the following:
DataSource = yourList.ToList()

C# Trying to find an unbound binding source [duplicate]

I am creating a ComboBox array dynamically and the DataSource for all the ComboBox is a single integer list that contains some integers. But when I change a value say X in any one combo box then all other combo values get reset to value X.
So here is the situation:
All combo box controls are bound to a single list
When I change selected item of a combo box, selected item of all other combo box controls also change.
How can I stop these behavior?
Since you are binding all combo boxes to the same data source - a single list - they are using a single BindingManagerBase.
So when you choose an item from one of combo boxes, the current Position of the shared binding manager base changes and all combo boxes goes to that position of their shared data source.
To solve the problem you can bind them to different data source:
You can bind them to yourList.ToList() or any other list for example different BindingList<T>.
combo1.DataSource = yourList.ToList();
combo2.DataSource = yourList.ToList();
You can use different BindingSource for them and set your list as DataSource of BindingSource
combo1.DataSource = new BindingSource { DataSource= yourList};
combo2.DataSource = new BindingSource { DataSource= yourList};
Also as another option:
You can use different BindingContext for your combo boxes. This way even when you bind them to a single list, they are not sync anymore.
combo1.BindingContext = new BindingContext();
combo1.DataSource = yourList;
combo2.BindingContext = new BindingContext();
combo2.DataSource = yourList;
In fact all controls of the form use a shared BindingContext. When you bind 2 controls to a same data source, then they also use the same BindingManagerBase this way, when you for example move to next record, all controls move to next record an show value from bound property of next record. This is the same behavior that you are seeing from your combo boxes. Being sync for controls which are using the same BindingManagerBase is a desired behavior. Anyway sometimes we don't need such behavior. The post shares the reason and the solution.

Strange behavior of Windows Forms combobox control

I am developing a small desktop app, and there are several drop-down lists (combobox-es) on my form. I populate a list of strings, which will be used as data source for all of them. Here is example from my Form.cs class:
List<string> datasource = new List<string>();
datasource.Add("string 1");
datasource.Add("string 2");
Then I set this list as a data source to several comboboxes:
cmbDataType1.DataSource = datasource;
cmbDataType2.DataSource = datasource;
This all happens in same method, which is called from the Form constructor.
Here is the strange part: after I change a selected value in one of them, the same value will be set in the other one. There are no SelectedIndexChange events set. I have messed up somewhere, but I cant put my finger where...
The behavior that you see is by design. When you bind the same object as the data source for multiple controls, all the controls share the same binding source.
If you explicitly assign a new binding source to each control, even while using the same data source, all controls will be unbound and will act independent of each other:
cmbDataType1.DataSource = new BindingSource(datasource, "");
cmbDataType2.DataSource = new BindingSource(datasource, "");
You should set a new BindingContext for the control before binding the dataSource the next time:
cmbDataType1.BindingContext = new BindingContext();
cmbDataType1.DataSource = datasource;
cmbDataType2.BindingContext = new BindingContext();
cmbDataType2.DataSource = datasource;
Since you are binding to the same exact datasource that is the expected behavior. You will want to change your binding to be a OneWay binding or use different objects if you don't want the selecteditem to change.

Refreshing ComboBox Data Binding in C# and .NET 4.0

I have a ComboBox (Windows Forms) that is bound to a List. It is created at design time. When the List contents are changed my code calls a function to refresh the data binding. This works fine for .NET 3.5:
BindingData.SuspendBinding();
DataSource = null;
DataSource = BindingData;
BindingData.ResumeBinding();
I have switched to .NET 4.0 and it has stopped working. Specifically after stepping through this code the VS debugger shows BindingData.DataSource refers to a list with 127 items, but the ComboBox Items property contains zero items.
See this SO question along a similar theme: ComboBox Items Count Doesn't Match DataSource.
I have tried everything I can think of. Currently my code looks like the following and still doesn't work:
BindingData.SuspendBinding();
DataSource = null;
DataSource = BindingData;
BindingData.ResumeBinding();
BindingContext Dummy = this.BindingContext;
Invalidate();
PerformLayout();
I tried switching from List to BindingList and that didn't help. I had to switch from .NET 3.5 to .NET 4.0 against my will so this is pretty frustrating. I'm sure there is a specific sequence that works. Any ideas?
This is how I am attaching the data source to the ComboBox:
private BindingSource BindingData = new BindingSource();
BindingData.DataSource = Nodes;
DataSource = BindingData;
thanks, Andy
I solved it. I guess at some point I made what I thought was a minor change but actually wasn't. This code was moved from being called when the ComboBox is being displayed to when it was being created. It didn't yet have a handle and so the data binding cannot be refreshed.
I added another refresh of the databinding again in a ComboBox.HandleCreated event and it works.
thanks, Andy
Why you're suspending and resuming the BindingSource? If you just change your DataSource there will be no performance pitfalls.
According to How to: Bind a Windows Forms ComboBox or ListBox Control to Data you can use the ComboBox's DisplayMember property:
//Sample for C++ .NET:
List<String^>^ options = gcnew List<String^>();
options->Add("Option 1");
options->Add("Option 2");
comboBox.DataSource = options;
comboBox.DisplayMember = "Length";//this causes an DataSource update but the ComboBox would
//show an item's length instead of the item itself
comboBox.DisplayMember = ""; //reset -> the ComboBox calls each List item's ToString
//member
"Length" refers to a public property of the String class. Better would be a property that refers directly to the string's characters. The only remaining public property of String is Chars but I couldn't make it work. So we reset DisplayMember by comboBox.DisplayMember = "", causing the ComboBox to call each List item's (a String) ToString method => problem solved.
Other List entries than Strings can be handled by the ComboBox's properties DisplayMember and ValueMember (they also apply to other controls):
DisplayMember & ValueMember

WinForms DataGridView Alternative

I need to populate a list that has 3 columns.
First: Icon Image.
Second: A string.
Third: A string.
I started to wire up a DataGridView and it seem awfully large and powerful for my needs. I am not interested in displaying data in a grid similar to a spreadsheet and I do not require all the functionality that comes with this control. Is there a better alternative?
Thanks!
You could go for the ListView in View.Details view, as this is similar to the view that you see in Windows Explorer when in Details view.
Create a form and place on it an ImageList and a ListView named imageList1 and listView1 respectively. Then place the following code into the forms load method:
listView1.Columns.Add("Image");
listView1.Columns.Add("Text1");
listView1.Columns.Add("Text2");
listView1.SmallImageList = imageList1;
var icon = Icon.ExtractAssociatedIcon(#"c:\windows\explorer.exe");
imageList1.Images.Add(icon);
var item = new ListViewItem();
item.ImageIndex = 0;
var subItem1 = new ListViewItem.ListViewSubItem();
subItem1.Text = "Text 1";
var subItem2 = new ListViewItem.ListViewSubItem();
subItem2.Text = "Text 2";
item.SubItems.Add(subItem1);
item.SubItems.Add(subItem2);
listView1.Items.Add(item);
The code really couldn't hurt for some tidying up, but it calls out quite explicitly what it's doing and should hopefully make it quite clear how to use a ListView for this purpose.
You could try ListView. You'll want to use the Columns property and Details mode.

Categories

Resources