Bind list from class to combobox - c#

I'm currently writing a pretty small program in C# and have this list that I want to bind to a combobox. Now, I've put that list in a class, and want to bind that list to a combobox. The code below shows how far I've come so far:
Form
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Locaties locaties = new Locaties();
List<string> listofLocaties = locaties.retrieveLocations();
cboxLocToevoegen.DataSource = ???;
cboxLocOverzicht.DataSource = ???;
}
}
Class
class Locaties
{
public List<string> retrieveLocations()
{
List<string> LocatieList = new List<string>();
LocatieList.Add("Koelkast");
LocatieList.Add("Keukenlade");
LocatieList.Add("Voorraadruimte");
LocatieList.Add("Overige");
return LocatieList;
}
}
Now, I'm gonna be honest with you: my knowledge and experience with classes and methods is not perfect. That's why the solution might probably be simpler than I think. Please don't judge me on that, I'm still learning!
Anyway, I hope anyone can help me out with this!

Simply
cboxLocToevoegen.DataSource = listofLocaties ;
or directly
cboxLocToevoegen.DataSource = locaties.retrieveLocations();
you can also bind directly to a list of Locaties and then choose the property to display in the CB :
List<Locaties> listofLocaties = new List<Locaties>();
...
//Populate the list
...
cboxLocToevoegen.DataSource = listofLocaties ;
cboxLocToevoegen.DisplayMember = [a property of Locaties class];
// and the value of the CB could be another property of Locaties class:
cboxLocToevoegen.ValueMember = [the value property of Locaties class];
But ofc you have to write a new Locaties class :)

Related

Using a DataSource with an object in Windows Forms

I have been trying to create a small form application and I wanted to try out binding a DataGridView directly to a collection of objects.
I created the following classes
public class MyClassRepository
{
public List<MyClass> MyClassList { get; set; } = new List<MyClass> { new MyClass { Name = "Test" } };
}
public class MyClass
{
public string Name { get; set; }
}
and I added the following code to a form to test. I based this off of the code in the designer after setting the BindingSource through the UI (while following this walk through https://msdn.microsoft.com/en-us/library/ms171892.aspx)
var tmp = new BindingSource();
tmp.DataMember = "MyClassList";
tmp.DataSource = typeof(MyClassRepository);
When this didn't work I started running through the code behind BindingSource to see what was happening. The setter calls ResetList which tries to create a dataSourceInstance by calling ListBindingHelper.GetListFromType. This call ultimately calls SecurityUtils.SecureCreateInstance(Type) where type is a BindingList<MyClassRepository>. This passes null to args which is passed Activator.CreateInstance which returns an empty collection.
After this ListBindingHelper.GetList(dataSourceInstance, this.dataMember) is called. This method calls ListBindingHelper.GetListItemProperties which results in a PropertyDescriptor for my MyClassList property and assigns it to dmProp.
At this point GetList calls GetFirstItemByEnumerable(dataSource as IEnumerable) where dataSource is the previously created (and empty) instance of BindingList<MyClassRepository> and returns (currentItem == null) ? null : dmProp.GetValue(currentItem);.
The value of dmProp/MyClassList is never accessed and the BindingSource is never populated with the instance I created. Am I doing something wrong? If not is there a bug in the source code? It seems to me like either SecureCreateInstance(Type type, object[] args) should be called and MyClassList should be passed via args instead of the existing call to SecureCreateInstance(Type type) or the value of dmProp should be used regardless?
If that is not correct how do I make the Designers automatically generated code set the DataSource to an instance of the object? Or do I have to inherit from BindingSource? If the latter why does it give you the option to choose a class that does not inherit from BindingSource?
As Reza Aghaei points out, in the designer, setting the BindingSource.DataSource to the “MyClassRepository” may work, however you still need to initialize (create a new) MyClassRepository object. I do not see this line of code anywhere in the posted code: MyClassRepository myRepositiory = new MyClassRepository(); The data source is empty because you have not created an instance of “MyClassRepository” and as Reza points out, this is usually done in the forms Load event.
To keep it simple, remove the DataSource for the BindingSource in the designer and simply set up the BindingSource’s data source in the form load event like below. First, create a new “instance” of the MyClassRepository then use its MyClassList property as a data source to the BindingSource. I hope this helps.
MyClassRepository repOfMyClass;
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
repOfMyClass = new MyClassRepository();
bindingSource1.DataSource = repOfMyClass.MyClassList;
dataGridView1.DataSource = bindingSource1;
}
Edit-----
After further review… I agree that you should be able to do as you describe. I was able to get it working as expected with the code below.
BindingSource bindingSource1;
private void Form1_Load(object sender, EventArgs e) {
bindingSource1 = new BindingSource();
bindingSource1.DataSource = typeof(MyClassRepository);
bindingSource1.DataMember = "MyClassList";
dataGridView1.DataSource = bindingSource1;
}
I followed the same steps in the “designer” and it worked as expected. Is there something else I am missing? As you stated… using MyClassRepository mcr = new MyClassRepository() appears to be unnecessary. In addition, if you cannot get it to work using one of the two ways above… then something else is going on. If it does not work as above, what happens?
Edit 2
Without creating a “new” MyClassRepository, object was unexpected and I did not realize that new items added to the list/grid were going into the bindingSource1. The main point, is that without instantiating a “new” MyClassRepository object, the constructor will never run. This means that the property List<MyClass> MyClassList will never get instantiated. Nor will the default values get set.
Therefore, the MyClassList variable will be inaccessible in this context. Example in this particular case, if rows are added to the grid, then bindingSource1.Count property would return the correct number of rows. Not only will the row count be zero (0) in MyClassList but also more importantly… is “how” would you even access the MyClassList property without first instantiating a “new” MyClassRepository object? Because of this inaccessibility, MyClassList will never be used.
Edit 3 ---
What you are trying to achieve can be done in a myriad number of ways. Using your code and my posted code will not work if you want MyClassList to contain the real time changes made in the grid by the user. Example, in your code and mine… if the user adds a row to the grid, it will add that item to the “bindingSource” but it will NOT add it to MyClassList. I can only guess this is not what you want. Otherwise, what is the purpose of MyClassList. The code below “will” use MyClassList as expected. If you drop the “designer” perspective… you can do the same thing in three (3) lines of code... IF you fix the broken MyClassRepository class and create a new one on the form load event. IMHO this is much easier than fiddling with the designer.
Changes to MyClassRepository… added a constructor, added a size property and a method as an example.
class MyClassRepository {
public List<MyClass> MyClassList { get; set; }
public int MaxSize { get; set; }
public MyClassRepository() {
MyClassList = new List<MyClass>();
MaxSize = 1000;
}
public void MyClassListSize() {
MessageBox.Show("MyClassList.Count: " + MyClassList.Count);
}
// other list manager methods....
}
Changes to MyClass… added a property as an example.
class MyClass {
public string Name { get; set; }
public string Age { get; set; }
}
Finaly, the form load event to create a new MyClassRepository, set up the binding source to point to MyClassList and lastly set the binding source as a data source to the grid. NOTE: making myClassRepository and gridBindingSource global variables is unnecessary and is set this way to check that MyClassList is updated in real time with what the user does in the grid. This is done in the button click event below.
MyClassRepository myClassRepository;
BindingSource gridBindingSource;
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
try {
myClassRepository = new MyClassRepository();
gridBindingSource = new BindingSource(myClassRepository.MyClassList, "");
dataGridView1.DataSource = gridBindingSource;
}
catch (Exception ex) {
MessageBox.Show("Error: " + ex.Message);
}
}
private void button1_Click_1(object sender, EventArgs e) {
MessageBox.Show("Binding source count:" + gridBindingSource.Count + Environment.NewLine +
"MyClassList count: " + myClassRepository.MyClassList.Count);
}
I hope this makes sense. ;-)
Designer sets DataSource = typeof(Something) for design-time support, for example to let you choose DataMember from a dropdown or to let you choose the data source property from dropdown while setting up data-bindings.
How do I make the Designers automatically generated code set the
DataSource to an instance of the object?
Forcing the designer to do that doesn't make much sense, because the designer doesn't have any idea about what the real data source you are going to use to load data. It can be a web service, a WCF service, a business logic layer class.
So at run-time you need to assign an instance of your list to DataSource. For example in Load event of the form.

dynamic combobox and select particular item in combobox to execute certain things

I have a string array which contains filenames. a number of filenames vary depending on what endusers select. I would like know how to populate the string array onto combobox. Thanks for your help in advance,
Your requirement is simple. Create an ObservableCollection<string> named Items and fill it with your filenames:
public ObservableCollection<string> Items
{
get { return items; }
set { items = value; NotifyPropertyChanged("Items"); } }
}
Make sure that you implement the INotifyPropertyChanged Interface correctly in the class that has the property. Next, simply data bind this property to the ComboBox.ItemsSource property in XAML:
<ComboBox ItemsSource="{Binding Items}" />
Finally, ensure that you have set the DataContext of the control with the XAML to an instance of the class with the property:
Either:
DataContext = this; // if properties are defined in code behind
Or:
DataContext = new ClassWithProperty();
Here a simple way to achieve this
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
string[] files = new string[]{};
ObservableCollection<string> observableCollection = new ObservableCollection<string>(files);
comboBox1.ItemsSource = observableCollection;
}
}
If you have your full array of filenames, you may want to try something like this:
for(int i = 0; i < myStringArray.Length; i++)
{
ComboBox1.Items.Add(myStringArray[i]);
}
This should add all of the filenames into the combobox ComboBox1.

Data binding between enum to ComboBox

Public Class Person
{
private enum accountType
{
Savings,
Cheking
},
}
In Windows form I have a comboBox Account Type.
How can i bind data from Person Class to Windows form combobox. When I run the form combobox will show the enum list automatically. How can i solve it. Anybody help me.
One portion enum accountType will be public. I am new in C#.
Hei i hope this could help you
public enum AccountType
{
Savings,
Cheking
}
Write the following code in your Form1.cs file
I am assuming your Form name is Form1
public Form1 ()
{
InitializeComponent();
BindComboList();
}
private void BindComboList()
{
var values = Enum.GetValues(typeof(AccountType));
foreach (var item in values)
{
cmbAccountType.Items.Add(item);
}
}
You are done.
Try this;
cbaccountType.DataSource=Enum.GetValues(typeof(accountType));
where cbaccountType is you ComboBox.

Clear var defined in UserControl from main Form

I've a UserControl where I define some vars and also has some components like buttons, textbox and some others:
private List<string> bd = new List<string>();
private List<string> bl = new List<string>();
It's possible to access to those vars from namespace WindowsFormsApplication1? How? If I try to do this from private void recuperarOriginalesToolStripMenuItem_Click(object sender, EventArgs e) I got a error:
bl = new List<string>();
blYear.Enabled = true;
btnCargarExcel.Enabled = true;
filePath.Text = "";
nrosProcesados.Text = "";
executiontime.Text = "";
listBox1.DataSource = null;
What's the right way to do this?
EDIT: clarify
What I'm looking for is to clean values each time I access a menu item. For textBox and others components it works thanks to the suggestions made here but for List I don't know how to set it to null
you can always access any variable that you define, any control that you place on your UserControl at all those places, where you have placed your UserControl.
Just make sure, you have made your variables public and exposed your Controls through public properties i.e
suppose you have kept a TextBox on your UserControl for Names. In order to use it outside, you must expose it through a public property
public partial class myUserControl:UserControl
{
public TextBox TxtName{ get{ return txtBox1;}}
public ListBox CustomListBoxName
{
get
{
return ListBox1;
}
set
{
ListBox1 = value;
}
}
public List<object> DataSource {get;set;}
}
and you can use it on the form you have dragged this usercontrol i.e.
public partial form1: System.Windows.Forms.Form
{
public form1()
{
InitializeComponent();
MessageBox.Show(myUserControl1.TxtName.Text);
MessageBox.Show(myUserControl1.CustomListBoxName.Items.Count);
myUserControl1.DataSource = null;
}
}
similary you can expose your variables, through public properties. That way you can also control whether you want some of your variables to be readonly or what!
You need to expose a property and then access that property on the usercontrol-instance from your main form:
UserControl
public List<string> BD {get; set;}
Main form
MyUserControl.BD = new List<string>();

Bind Bindingsource to a list

I have a class like
internal class CalculationsDataRelations
{
public List<CalculationsDataRelation> Relations;
}
And trying to bind it to a datagridview using following code
relations = new CalculationsDataRelations();
bs = new BindingSource(relations, "Relations");
DgvRelations.DataSource = bs;
But I get exception "DataMember property 'Relations' cannot be found on the DataSource."
How to bind datagridview properly?
Binding has to happen with Properties, but your internal class is only providing a Field. Also, you haven't instantiated the List<CalculationsDataRelation> variable with "new".
Try changing it to something like this:
internal class CalculationsDataRelations {
private List<CalculationsDataRelation> relations = new List<CalculationsDataRelation>();
public List<CalculationsDataRelation> Relations {
get { return relations; }
}
}

Categories

Resources