WinForms Combobox: Fill with String and Object - c#

I already have seen that there are many Topics about this,but I am not able to make them work.
I have an Combobox which shall be filled with an List of String.
this.elementBox.DataSource = this.elementList;
this.elementBox.SelectedIndexChanged += new EventHandler(this.elementBox_SelectedIndexChanged);
If I put this into the Code my GUI does not appear, I suppose the assignment of the data is wrong. I already tried Bindingsource.
Then I want to fill an Combobox with an List of Objects and this does not work either. itemData is an Dictionary with an String as key and the Objectlist as value.
box1.DataSource = itemData["ele1"];
box1.DisplayMember = "Name";
box2.DataSource = itemData["ele2"];
box2.DisplayMember = "Id";
I tried to play around with DisplayMember and Value but I am not able to get it to work.
The Type of the List is MyItem:
class myItem{ int Id; Internal data;}
class Internal {String name;}
Obviously I want to show the myItem.data.name in the Combobox, but I do not know how to get it. Furthermore what is the difference of DisplayMember and Value?

DisplayMember expects a public property not a private field
Change the classes:
class myItem
{
public int Id {get; set}
public Internal data {get;set;}
}
class Internal
{
public string Name {get; set;}
}
Note also that the property names are case sensitive. So 'name' and 'Name' are considered to be different entities.
Further, if you are adding an object of 'myItem` class, you cannot get the combo box to access the a member of a member. You will have to do the fetching yourself:
class myItem
{
public int Id {get; set}
public Internal data {get;set;}
public string Name { get { return data.Name; }}
}
Now by setting DisplayMember to "Name" it will reference the Name property of myItem which in turn accesses the data.Name property.
If the list comes to you from somewhere else (you don't own the list class and thus cannot modify it's code), you will have to wrap the objects inside another class and replace the list with a list of the wrapped objects:
class myItemWrapper
{
private myItem _myItem;
public myItemWrapper(myItem item)
{
_myItem = item;
}
public override string ToString()
{
return _myItem.data.Name;
}
public myItem Item { get { return _myItem;}}
}
then you can get rid of the DisplayMember assignment
box1.DisplayMember = "Name";
as the ToString() will be called instead.
but you have to replace the
box1.DataSource = itemData["ele1"];
with a bit more code:
var wrapper = new List<myItemWrapper>();
foreach(var item in itemData["ele1"]);
wrapper.Add(new myItemWrapper(item));
box1.DataSource = wrapper;
And don't forget that, when you are handling the selected item in the listbox that you are no longer dealing with myItem objects, but myItemWrapper objects instead. So to access the actual myItem object you will have to use the Item property of the myItemWrapper class instead.

Related

ComboBox DataSource, strange behavior when items are of different types

The items of a combobox are based on a collection whose elements are of type Dog.
public class Dog {
public String Name { set; get; }
public String Breed { set; get; }
}
Usage:
public partial class MyForm: Form
{
private ArrayList dogs = new ArrayList();
public Form5()
{
InitializeComponent();
dogs.Add(new Dog() { Name = "Boby", Breed = "Pinscher" });
dogs.Add(new Dog() { Name = "Sid", Breed = "Labrador" });
comboBox1.DataSource = dogs;
comboBox1.DisplayMember = "Name";
}
}
Now i want to add a null element, but not by creating a dummy, empty object of Dog type: sometimes it's not possible.
Since DisplayMember is a String representing the name of a property, "Name" in this case, I thought that a different class type with the very same property would work.
This would allow for a very neat solution like this: 1) define a null-object (should be a singleton, but for the sake of brevity I keep it basic here):
public class NullObject
{
public String Name { get { return ""; } }
}
and then (2) I add it to the collection:
dogs.Add(new NullObject());
This DOESN'T work and what i get is a combo like this:
If I move the NullObject to the beginning, doing so:
dogs.Add(new NullObject());
dogs.Add(new Dog() { Name = "Boby", Breed = "Pinscher" });
dogs.Add(new Dog() { Name = "Sid", Breed = "Labrador" });
I'll get:
So it's as if WinForms caches the object type of the first element and then expect the following to be the same type, otherwise fallback on ToString() method (that BTW when feasible may be a solution).
Is this a bug or is it documented somewhere? Is there another way of implementing this null-object pattern that works in combination with ComboBox?
UPDATE 1:
ValueMember seems to behave as initially supposed, that is it looks for a property of the specified name even if object types are different along the DataSource collection.

Assign a Collection class to the items of a list box

I'm sure there should be an easier way to do this. I have a class based on Collection, and that class is a collection of another class. Currently, whenever I have a new item in my class, I assign that item to the listbox. I can't seem to figure out a way to assign all of the values in the collection class, because it is a collection, to the collection of the listbox. Any ideas? Thanks
Ok, what I've done so far is I have a tostring override in the Class used in the collection. This is what I want the listbox to show.
public override string ToString()
{
return string.Format("{0} {1}: {2}", tTypev.ToString(),
Datev.ToString("MM/dd/yyyy"), Amountv.ToString("C"));
}
Which is what I want each item in the listbox to show.
class Transactions : System.Collections.CollectionBase
{
...
}
Is my collections class, containing a collection of the other class, Tansaction. Curently, I use the lstTransactions.Items.Add(), .Remove, .RemovAt, etc to add items to the list box, and the .Add(), .Remove, etc to add items to the Collection Class, Transactions. But I'm trying to decrease reliance on outside controls, and only use them in a few lines of code. I was trying to use something like:
lstTransactions.DataSource = (Transaction)myTrans;
but that didn't seem to work. Mainly because I couldn't figure out what property DataSource took.
I also tried:
lstTransactions.Items =
but it told me that items was read only.
In Windows Form:
You could used DataSource property to bind a collection of object.
DisplayMember property to the name of a property in the data source object.
Sample Code:
In the below sample the output list box would display 2 items : Apple and Ball.
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
EmployeeCollection data = new EmployeeCollection();
data.AddEmployee(new Employee("Apple", 25));
data.AddEmployee(new Employee("Ball", 50));
listBox1.DataSource = data;
listBox1.DisplayMember = "Name";
}
}
public class Employee
{
public Employee(string name, int age)
{
this.Name = name;
this.Age = age;
}
public int Age
{
get; private set;
}
public string Name
{
get; private set;
}
}
public class EmployeeCollection : System.Collections.CollectionBase
{
public void AddEmployee(Employee employee)
{
this.List.Add(employee);
}
}
}
In WPF:
You could use ItemSource property of ListBox to bind a collection (which may be a List, Enumerable, Collections.._ do the job
Sample snippet:
IList<string> data = new List<string>() {"A", "B"};
ListBox listBox = new ListBox();
listBox.ItemsSource = data;

Retrieve Listview items and display a column data as combo box display member and other value as value member

I have a list view with two columns- name and number. I want to read all these items and assign name to a combo box display member and number to value member. I have tried thinking the approach to follow but couldn't help myself. This is what I have tried. How should I proceed?
public class numbers
{
public string name;
public string number;
}
public class names : List<numbers>
{
}
names cname = new names();
public void addcontacts()
{
foreach(ListView lv in bufferedListView1)
{
//No idea how to proceed
First you set your own type:
public class myContact
{
public string Name { get; set; }
public string Number { get; set; }
public myContact(string name, string number)
{
this.Name = name;
this.Number = number;
}
public override string ToString()
{
return Name;
}
}
Then you transfer all items from the listview to the combobox like this:
foreach (ListViewItem item in listView1.Items)
{
comboBox1.Items.Add(new myContact(item.Text, item.SubItems[0].Text));
}
This example assumes, that each listviewitem holds the name and that its first child holds the number.
When you add objects to the combobox, C# will use the objects' ToString() method to create something that you can actually see when the program is running. You override the default ToString() method with your own and only return the name. If you want to use the selection from the combobox you just cast the selectedItem back to myContact and can access the number there. Welcome to OOP :)

DataBinding: 'System.Web.UI.Pair' does not contain a property with the name 'First'

I'm data binding a list of pairs to a drop down list, for some reason it's not working and I'm intrigued.
The code I am using is :
public void BindDropDown(List<Pair> dataList)
{
ddlGraphType.DataTextField = "First";
ddlGraphType.DataValueField = "Second";
ddlGraphType.DataSource = dataList;
ddlGraphType.DataBind();
}
I'm getting this exception, which is a lie!
DataBinding: 'System.Web.UI.Pair' does not contain a property with the name 'First'.
Thanks in advance.
Added
I know what the exception means, but a pair object does contain the First and Second properties, that's where the problem lies.
First and Second are Fields not properties of Pair type. You need to create a class with two properties:
public class NewPair
{
public string First { get; set; }
public string Second { get; set; }
}
EDIT: Use of Tuple : suggested by #Damien_The_Unbeliever & #Chris Chilvers
List<Tuple<string, string>> list = new List<Tuple<string, string>>()
{
new Tuple<string,string>("One","1"),
new Tuple<string,string>("Two","2"),
};
ddlGraphType.DataTextField = "Item1";
ddlGraphType.DataValueField = "Item2";
ddlGraphType.DataSource = list;
ddlGraphType.DataBind();
Theat means the target property must be a dependency property. This also means that you cannot bind a field and Pair.First is field not property
public sealed class Pair
{
}
Fields:
Public field First Gets or sets the first object of the object pair.
Public field Second Gets or sets the second object of the object pair.
See MSDN.
Probably you've forgot the {get; set;} after declaring the properties.
public class A
{
//This is not a property
public string Str;
//This is a property
public string Str2 {get; set;}
}

Populating DataGridView using DataGridView.DataSource property and BindingSource

The following two code snippets populate a BindingSource which is later assigned to
a DataGridView.DataSource.
When the concrete class QuotesTool.LineItem is used (first snippet) the grid DOES NOT display the appropriate data:
BindingSource lineList = new BindingSource();
foreach (XElement y in _lines.Elements())
{
lineList.Add(new QuotesTool.LineItem(
y.Element("Vendor").Value,
y.Element("Model").Value,
y.Element("Selling_Unit").Value,
y.Element("Net_Price").Value,
y.Element("Spec").Value
));
}
But, if an anonymous type is used the grid displays data OK:
foreach (XElement y in _lines.Elements())
{
lineList.Add(
new {
vendor = y.Element("Vendor").Value,
Model = y.Element("Model").Value,
UOM = y.Element("Selling_Unit").Value,
Price = y.Element("Net_Price").Value,
Description = y.Element("Spec").Value
});
}
Any ideas would be appreciated. Thanks.
Hard to tell without seeing QuotesTool.LineItem, but by default to be useful, each member:
must be public
must be a property (not a field)
must not be marked [Browsable(false)]
The issue here is usually one of the first two. For example, none of these will work by default:
public string Vendor;
internal string Vendor {get;set;}
[Browsable(false)] public string Vendor {get;set;}
but this will:
public string Vendor {get;set;}
Note that it doesn't have to be an automatically implemented property, nor does it need to be writeable:
private readonly string vendor;
public string Vendor { get { return vendor; } }

Categories