I have an object with 2 element fields for C#, and I have inserted them into an arraylist. I am trying to get them to display on the combobox.
This is what I currently have
ArrayList mylist = new ArrayList();
mylist.Add(new myobject("name1", "value1"));
mylist.Add(new myobject("name2", "value2"))
mylist.Add(new myobject("name3", "value3"));
ComboBox1.ItemsSource = drinksArray;
The following code would just display 3 elements which are "ClassName.myobject" for my combobox.
I am trying to get it to display "name1", "name2" and "name3".
I have a getName() method for my object but I do not know how to implement it into the combobox.
You have to set the ComboBox.DisplayMemberPath.
https://msdn.microsoft.com/en-us/library/system.windows.controls.itemscontrol.displaymemberpath(v=vs.110).aspx
Call the getName() method in the ToString() method of the myobject class:
public class myobject
{
...
public override string ToString()
{
return getName();
}
}
Or set the DisplayMemberPath to the name of a public property of the myobject class that returns the value you want to display as suggested by #zambonee:
ComboBox1.DisplayMemberPath = "Name";
I would add a readonly property to your myobject class that returns getName(), then set DisplayMemberPath on the ComboBox to the name of that property.
If the name can ever change, you will want to implement INotifyPropertyChange and raise its event for the property whenever the value should be updated.
Related
How to extract a selected item from Listbox as an object. Currently, I'm taking all records from DB and I add them to the Listbox in the following way:
var allEmployees = GetAll();
foreach (var emp in allEmployees)
{
var empFull = $"{emp.Id} - {emp.Name} {emp.Surname} - {emp.Email}";
listBoxViewEmp.Items.Add(empFull);
}
However, I find it challenging to make the listBoxViewEmp.SelectedItem to object since I'm taking the entire string that contains id, name, surname, and email.
private void btnUpdate_Click(object sender, EventArgs e)
{
if(listBoxViewEmp.SelectedItem != null)
{
var newForm = new UpdateForm(listBoxViewEmp.SelectedItem);
newForm.Show();
}
else
{
MessageBox.Show("Please select employee first");
}
}
What is the best way to handle this kind of issue?
Update:
Here is my attempt, but I got only objects now in the listbox
var allEmployees = GetAll();
foreach (var emp in allEmployees)
{
var empFull = (Employee)emp;
listBoxViewEmp.Items.Add(empFull);
}
enter image description here
The string that appears for any object added as an item to a ListBox control will be the return value of the ToString method of that object. In your case, you added a string directly to the list. So there's (likely) no way to recover the original object from the formatted string you created for that object.
Instead, override ToString for your Employee object (if appropriate to do so).
Alternatively, you can create a wrapper class whose job it is to remember the original object and to provide a custom ToString implementation for the remembered object. Such a generic formatter class might look like:
public class Formatter<T>
{
public Formatter(T obj, Func<T, string> fnFormat)
{
this.obj = obj;
this.fnFormat = fnFormat;
}
public T obj;
public Func<T, string> fnFormat;
public override string ToString() => fnFormat(obj);
}
Then, when you add items to the list box, add a Formatter wrapping that item instead. Its ToString method will be called, which will call the custom formatter for that item.
foreach (var employee in employees)
{
this.listBox1.Items.Add(new Formatter<Employee>(employee,
emp => $"{emp.Id} - {emp.Name} {emp.Surname} - {emp.Email}"));
}
And to access the original Employee, case the SelectedItem back to the Formatter<Employee> and access its remembered object field obj. Now you have the original Employee object back (or DB record or entity or whatever it was originally.) Example usage:
private void button1_Click(object sender, EventArgs e)
{
Employee employee = (this.listBox1.SelectedItem as Formatter<Employee>)?.obj;
this.label1.Text = employee?.Id.ToString();
}
You can use databinding for this. Make a new readonly property which will return computed string you want. Than ListBox has some properties you can use:
Datasource - source of data which will be displayed. You can set here just simple List<Employee>.
DisplayMember - you set the name of the property, which value you want to see in the ListBox.
ValueMember - you set the name of the property which value you want to get for selected item using ListBox's SelectedValue property.
So you can do it this way:
// You should set these two properties in form's designer.
listBoxViewEmp.DisplayMember = "Info"; // "Info" is that new readonly property.
listBoxViewEmp.ValueMember = "Id";
var allEmployees = GetAll().ToList();
listBoxViewEmp.DataSource = allEmployees;
That's it. Now:
You will see in the listbox what you want to see there.
listBox.SelectedItem returns whole your Eployee object.
listBox.SelectedValue returns the Id value of selected employee.
If you have access to the Employee class, do that :
Main code:
var allEmployees = GetAll();
foreach (var emp in allEmployees)
{
var empFull = (Employee)emp;
listBoxViewEmp.Items.Add(empFull);
}
In class code :
class Employee
{
...
public override string ToString()
{
return $"{this.Id} - {this.Name} {this.Surname} - {this.Email}";
}
}
Now you are able to get the items from the listbox as Employee and it will also replace "JustTest.Models.Employee" in the ToString above.
I need to derive a class from ComboBox and change its Items property. Here is my code:
public class MyComboBox2 : ComboBox
{
private MyObjectCollection MyItems;
public MyComboBox2()
{
MyItems = new MyObjectCollection(this);
}
//new public ComboBox.ObjectCollection Items
new public MyObjectCollection Items
{
get {
return MyItems;
}
}
}
public class MyObjectCollection : ComboBox.ObjectCollection
{
public MyObjectCollection(ComboBox Owner) : base(Owner)
{
}
new public int Add(Object j)
{
base.Add(j);
return 0;
}
}
As you can see, I am creating a new class MyComboBox2 derived from ComboBox. This class is supposed to have a new Items property, which would be of type MyObjectCollection rather than ComboBox.ObjectCollection. I have a comboBox called myComboBox21 on the form of type MyComboBox2. When I want to add a new object to my ComboBox, I would execute code like this: myComboBox21.Items.Add("text");
In this case, I end up executing the Add method of MyObjectCollection that I implemented myself. However, the ComboBox on the form does not end up containing value 'text'. I am attaching screenshot of debugger showing ComboBox values. MyComboBox21 contains Items Property (which does contain "text", as shown in screenshot "2.png"), and it contains base.Items (which does not contain "text" as shown in "1.png"). So, apparently, MyComboBox21 contains its own Items property (which I can insert to), and its base class's Items property, which gets displayed in the Windows Form. What can I do so that I can successfully add to comboBox with my own method? Since my ComboBox has 2 Items properties, can I specify which Items property's values should be shown in ComboBox?
Just by looking very quickly on the code:
The original Item index is declared as
virtual Object this[int index] {...}
Does the new keyword maybe be exchanged by override in your implementation in order to make the runtime pick the intended code?
I have a list that contains custom objects. These objects have different properties, and I have ~100 of them. I want to create a list of them in a listbox, but the listbox displays only
MyNamespace.MyClass
MyNamespace.MyClass
MyNamespace.MyClass
MyNamespace.MyClass
...
Is it possible to make the listbox display a certain value for each item? Lets say my objects have an ID string value. Can I display the ID for each item without discarding my objects' other properties?
I currently fill the listbox this way:
lbox.Items.Clear();
lbox.Items.AddRange(list.ToArray());
Set the DisplayMember to the property of your class that you'd like the user to see.
lbox.Items.Clear();
lbox.Items.AddRange(list.ToArray());
lbox.DisplayMember = "ID"; // ID is a public property in MyClass
Lets say you MyClass looks like this:
public class MyClass
{
public int Id { get; set; }
}
There are two options available.
You can use DataBinding for that.
Set the DisplayMember to the propertie of your MyClass which you would like to display
lbox.DisplayMember = "Id";
Set the items using the DataSource propertie of your ListBox
lbox.DataSource = list.ToArray();
You can simple override the ToString method of your MyClass object and return the text you would like to display.
Override the ToString method of your MyClass
public class MyClass
{
public int Id { get; set; }
public override string ToString()
{
return Id.ToString();
}
}
Set the items the same way as you mentioned
lbox.Items.AddRange(list.ToArray());
More Information
MSDN: ListControl.DisplayMember Property
MSDN: Object.ToString Method
Without discarding the object you can attach the object to the tag after.
list.ToList().ForEach(item => lbox.Items.Add(new ListItem(item.ID){Tag = item});
then to retreive it :
var myitem = ((ListItem)lbox.SelectedItem).Tag as MyClass;
Try using Linq.
lbox.Items.AddRange(list.Select(x => x.ID).ToArray());
Where ID is a property with the value you want to show.
You can also override ToString() in the class.
Is there a way to override the Add() method of Combobx?
The reason I ask this is that I want to Add the class objects to my combbox but for display I want it to show the Name of my objects.
so for example: combbox.Items.Add(myClassObject)
but what we actually see in the combbobx as the user will show as myClassObject.Name
If I right understood your request, you can do that using the binding:
Pseudocode:
comboBox.DataSource = collectionOfData;
comboBox.DisplayMember = "Name";
The data will be added to combo but visualized will be the Name property of the "data".
This all done using DisplayMember Property.
Because ComboBox uses ToString() method of object which is added in Items collections to display on the UI, so override ToString of myClassObject to return whatever you want, it is simple:
class myClassObject
{
public override string ToString()
{
return "whatever you want";
}
}
With this way you do not touch ComboBox Control
You can develop extension Method
public static class Extension
{
public static void Add(this ComboBox, myClassObject value)
{
...
}
}
Create a new control that extends combobox control. Then override Add method.
I have the following class
public class Car
{
public Name {get; set;}
}
and I want to bind this programmatically to a text box.
How do I do that?
Shooting in the dark:
...
Car car = new Car();
TextEdit editBox = new TextEdit();
editBox.DataBinding.Add("Name", car, "Car - Name");
...
I get the following error
"Cannot bind to the propery 'Name' on the target control.
What am I doing wrong and how should I be doing this? I am finding the databinding concept a bit difficult to grasp coming from web-development.
You want
editBox.DataBindings.Add("Text", car, "Name");
The first parameter is the name of the property on the control that you want to be databound, the second is the data source, the third parameter is the property on the data source that you want to bind to.
Without looking at the syntax, I'm pretty sure it's:
editBox.DataBinding.Add("Text", car, "Name");
editBox.DataBinding.Add("Text", car, "Name");
First arg is the name of the control property, the second is the object to bind, and the last, the name of the object property you want to use as the data source.
You are quite close the data bindings line would be
editBox.DataBinding.Add("Text", car, "Name");
This first parameter is the property of your editbox object that will be data bound. The second parameter is the data source you are binding to and the last parameter is the property on the data source that you want to bind to.
Bear in mind that the data binding is one way so if you change the edit box then the car object gets updated but if you change the car name directly the edit box is not updated.
Try:
editBox.DataBinding.Add( "Text", car", "Name" );
Using C# 4.6 syntax:
editBox.DataBinding.Add(nameof(editBox.Text), car, nameof(car.Name));
if car is null, then the above code will fail in a more conspicuous way than using literal string to represent the datamember of car
I believe that
editBox.DataBindings.Add(new Binding("Text", car, "Name"));
should do the trick. Didn't try it out, but I think that's the idea.
You're trying to bind to the "Name" of the TextEdit control. The name is used for accessing the control programmatically, and cannot be bound against. You should be binding against the Text of the control.
The following is generic class that can be used as a property and implements INotifyPropertyChanged used by bound controls to capture changes in the property value.
public class NotifyValue<datatype> : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged = delegate { };
datatype _value;
public datatype Value
{
get
{
return _value;
}
set
{
_value = value;
PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Value"));
}
}
}
It can be declared like this:
public NotifyValue<int> myInteger = new NotifyValue<int>();
and assigned to a textbox like this
Textbox1.DataBindings.Add(
"Text",
this,
"myInteger.Value",
false,
DataSourceUpdateMode.OnPropertyChanged
);
..where "Text" is the property of the textbox, 'this' is current Form instance.
A class does not have to inherit the INotifyPropertyChanged class. Once you declare an event of type System.ComponentModel.PropertyChangedEventHandler the class change event will be subscribed to by the controls databinder
it's
this.editBox.DataBindings.Add(new Binding("Text", car, "Name"));