C# combobox overridden ToString - c#

I am experiencing some problems while working with ComboBox.
The display member for my combobox is not being populated by the overridden ToString method of class MAP.
Here is my code:
Form1.cs:
private void Form1_Load(object sender, EventArgs e) {
...
...
MAPList MAP = new MAPList();
comboBox1.DataSource = MAP.All;
comboBox1.ValueMember = "Code";
...
...
}
MAPList.cs:
public class MAPList {
public readonly List<MAP> All;
public MAPList() {
All = new List<MAP>();
var MapData = // Getting map data
foreach(MAP m in MapData) {
All.Add(new Map(m.Name, m.Code));
}
}
}
MAP.cs:
public class MAP {
public readonly string Name;
private string code;
public string Code { get { return code; } }
public RadioCode(string Name, string Code) {
this.Name = Name;
this.code = Code;
}
public override string ToString() {
return String.Format("{0}: {1}", Name, Code);
}
}

ToString will not be called if you set ValueMember. If you do not set ValueMember it will work as expected but then of course Code will not be used as the selected value of the ComboBox.
Alternatively, if you wish to use ValueMember you may also want to set DisplayMember. You can create a property on your MAP that is used for display, i.e.:
public class MAP
{
public readonly string Name;
private string code;
public string Code { get { return code; } }
public string Display { get { return ToString(); } }
public MAP(string Name, string Code)
{
this.Name = Name;
this.code = Code;
}
public override string ToString()
{
return String.Format("{0}: {1}", Name, Code);
}
}
In the form you can then set DisplayMember:
MAPList MAP = new MAPList();
comboBox1.DataSource = MAP.All;
comboBox1.ValueMember = "Code";
comboBox1.DisplayMember = "Display";

This is because you've set your ValueMember property to "Code", so the values in the combobox are not your Map objects but rather the strings corresponding to their Code properties.
If you remove this line:
comboBox1.ValueMember = "Code";
...it will work as you expect.
If you want the ComboBox to display its items according to your Map type's ToString method, then Jakob's answer is right on: create a property on your Map type that provides a string formatted exactly how you want it, and set the DisplayMember property of the ComboBox to the name of this property.

this could be because u r using ValueMember. use DisplayMember Property, add another property on the Map class in the get of this property return the formatted string.

I know this is an old post, but if someone wants to use ToString() without creating a property to just call ToString(), you'll have to explicitly set the DisplayMember value to an empty string like this:
Form1.cs:
private void Form1_Load(object sender, EventArgs e) {
...
...
MAPList MAP = new MAPList();
comboBox1.DataSource = MAP.All;
comboBox1.ValueMember = "Code";
comboBox1.DisplayMember = ""; // Explicitly set it to an empty String
...
...
}

Related

Why does ValueMember override an empty DisplayMember

When I set a DataSource on a control and want to use .ToString() as DisplayMember, I need to set the DisplayMember last or the ValueMember will override it.
MSDN on empty string as display member:
The controls that inherit from ListControl can display diverse types of objects. If the specified property does not exist on the object or the value of DisplayMember is an empty string (""), the results of the object's ToString method are displayed instead.
Code to reproduce:
Class:
class SomeClass
{
public string PartA { get; set; }
public string PartB { get; set; }
public string WrongPart { get { return "WRONG"; } }
public override string ToString()
{
return $"{PartA} - {PartB}";
}
}
Form:
var testObj = new SomeClass() { PartA = "A", PartB = "B" };
comboBox1.DataSource = new [] { testObj };
comboBox1.DisplayMember = "";
comboBox1.ValueMember = "WrongPart";
comboBox2.DataSource = new[] { testObj };
comboBox2.ValueMember = "WrongPart";
comboBox2.DisplayMember = "";
You can try it by making a new form and adding 2 combobox's.
Result:
Conclusion and question:
This can be easily fixed by setting them in the correct order however this is prone to errors, it also does not show this behavior if I use an actual property as DisplayMember instead of ""/ToString.
I would really like to know why it displays this behavior and if I could possibly set .ToString() explicitly as DisplayMember (for code clarity).
I have searched in the reference source and found this bit:
if (!newValueMember.Equals(valueMember)) {
// If the displayMember is set to the EmptyString, then recreate the dataConnection
//
if (DisplayMember.Length == 0)
SetDataConnection(DataSource, newValueMember, false);
SetDataConnection method signature:
private void SetDataConnection(object newDataSource, BindingMemberInfo newDisplayMember, bool force)
This sets a new DisplayMember
displayMember = newDisplayMember;
so now we've come to the root of the issue

C# populate a combo box from a method

What I would like to do is to populate a drop down menu from a database.
First of all I plan to use a combo box.
I have created an object that contains the data that I need to take from the database. The object is as follows
namespace RLMD
{
public class FlashCardLevel
{
private int intFCLId;
private String strFCLName;
public FlashCardLevel(int intFCLId, String strFCLName)
{
this.intFCLId = intFCLId;
this.strFCLName = strFCLName;
}
public int IntFCLId
{
get { return intFCLId; }
set { this.intFCLId = value; }
}
public String StrFCLName
{
get { return strFCLName; }
set { this.strFCLName = value; }
}
}
}
What I need to do is to add a list of items from a database, but for ease of use I have simulated given some sample data.
public List<FlashCardLevel> Rifle(List<FlashCardLevel> fcLevel)
{
fcLevel.Add(new FlashCardLevel(1, "Severe"));
fcLevel.Add(new FlashCardLevel(2, "Moderate"));
fcLevel.Add(new FlashCardLevel(3, "Mild"));
fcLevel.Add(new FlashCardLevel(4, "Slight"));
return fcLevel;
}
I'm calling the method here.
List<FlashCardLevel> fcLevel = new List<FlashCardLevel>();
talkToDatabase.Rifle(fcLevel);
this.comboCardLevel.DataSource = fcLevel;
this.comboCardLevel.DisplayMember = "Name";
this.comboCardLevel.ValueMember = "Value";
The combobox is displaying no information.
I would appreciate any help
Updated:
The DisplayMember Property should be referring to FlashCardLevel (class), Property StrFCLName and ValueMember should be pointing to IntFCLId.
List<FlashCardLevel> fcLevel = new List<FlashCardLevel>();
talkToDatabase.Rifle(fcLevel);
this.comboCardLevel.DataSource = listFromDatabase;
this.comboCardLevel.DisplayMember = "StrFCLName";
this.comboCardLevel.ValueMember = "IntFCLId";
The DisplayMember and ValueMember should point to your properties name.
this.comboCardLevel.DisplayMember = "IntFCLId";
this.comboCardLevel.ValueMember = "StrFCLName";

Confused about about how to iterate this collection

What I want to do is get all available network adapters
with key and value pairs.So I have class named Adapters consist of two variable first one is to keep
registry key and the second one is to
keep Adapter name such as (wireless ,local area and so on).And this is my code
List<Adapters> GetAdapterNames(string regPath)
{
List<Adapters> list = new List<Adapters>();
RegistryKey key = RootNode(regPath, false);
if (key != null)
{
string[] par = key.GetSubKeyNames();
foreach (string node in par)
{
if (node != "Descriptions")
{
RegistryKey keys = RootNode(regPath+"\\"+node + "\\Connection", false);
string name = keys.GetValue("Name").ToString();
list.Add(new Adapters(name,node));
}
}
return list;
And this is my adapterclass
class Adapters
{
private string _name;
private string _val;
public string Name
{
get { return _name; }
set { _name = value; }
}
public string Val
{
get { return _val; }
set { _val = value; }
}
public Adapters(string name,string value)
{
_name = name;
_val = value;
}
}
The problem is how can I give this list to the combobax and loop through in it .
something like this
private const string ADAPTER_PATH =
#"SYSTEM\ControlSet001\Control\Network\{4D36E972-E325-11CE-BFC1-08002BE10318}";
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
List<Adapters>adapters= GetAdapterNames(ADAPTER_PATH);
combobax.valueMember=//list.name
combobax.displayMember=list.node;
}
Based on the example you've got (please see How to create a Minimal, Complete, and Verifiable example for advice on how to provide a good code example in your question), the following would work:
private void Form1_Load(object sender, EventArgs e)
{
List<Adapters>adapters= GetAdapterNames(ADAPTER_PATH);
combobax.DataSource = adapters;
combobax.ValueMember = "Name";
combobax.DisplayMember = "Val";
}
You can assign any implementation of IList to the DataSource property of the ComboBox.
The ValueMember and DisplayMember properties can be used to control what value is returned from the SelectedValue property and what string is displayed in the ComboBox itself, respectively. They are string values which contain the name of a property of the class of the objects used to populate the ComboBox.
Notes:
I have no idea if combobax is in fact the correct name for the field in your form that contains the reference to the ComboBox object. That's what you typed, so it's what I've left here.
It seems a little odd to display the node registry key name, and use the "friendly" adapter name as the value member. But again, that's what you typed, so that's what I've shown in the example.

listbox items not displaying properly

I have a listbox and a ListItem object which I am adding to the listbox so that I can retrieve a value from the selected item which is different then the displayed member.
class ListItem
{
public string DisplayMember;
public string ValueMember;
public ListItem(string n,string v){
DisplayMember = n;
ValueMember = v;
}
}
public CompareTimeFramesForm()
{
InitializeComponent();
listBox1.Items.Add(new ListItem("# of Bookings", null));
listBox1.Items.Add(new ListItem("People", "guaranteed_count"));
}
This is a winform FYI.
The problem I am having is the item shown in the actual listbox has the object rather then the string I would like to be displayed in the first argument of the ListItem constructor.
It looks like Bookings.Helpers.ListItem rather then "# of Bookings"
In the designer I changed the displayMember property to DisplayMember and its not working.
From MSDN:
When an object is being added to the ListBox, the control uses the text defined in the ToString method of the object unless a member name within the object is specified in the DisplayMember property.
ListBox will convert item to string calling ToString(). In your case you just need to change your ListItem class like this:
class ListItem
{
public string DisplayMember;
public string ValueMember;
public ListItem(string n,string v) {
DisplayMember = n;
ValueMember = v;
}
public override string ToString() {
return DisplayMember;
}
}
As alternative you can se the DisplayMember property (in designer or with code) to use your property (you called that property DisplayMember but its name is free because it must be specified and it doesn't use any convention):
listBox1.DisplayMember = "DisplayMember";
try this it should work for you!
class ListItem
{
public string DisplayMember;
public string ValueMember;
public ListItem(string n,string v){
DisplayMember = n;
ValueMember = v;
}
}
public CompareTimeFramesForm()
{
InitializeComponent();
listBox1.Items.Add(new ListItem("# of Bookings", null).DisplayMember);
listBox1.Items.Add(new ListItem("People", "guaranteed_count").DisplayMember);
}

Proper way to map combo box lines to their corresponding strategy objects?

I have a situation that is pretty simple, and I'd like to know the ideal way to do it.
I have a combo box. Each line of the combo box corresponds to a particular strategy object.
What is the proper way to map the combo box lines to the strategy object.
The way I was doing it seems overly complicated, and I'm pretty much guaranteed there is a simple standard way to do this.
Thank you.
EDIT:
I had the data in a Dictionary, where the string was the text for the combobox, and the object was the strategy... But this isn't ordered... And I just know there is some extremely simple way to do it.
SOLUTION:
I used this solution, not feeling comfortable putting presentation logic in the data classes:
private partial class HtmlTransformState : AbstractHtmlEditFormState
{
private Dictionary<string, ITransformStrategy> strategies = new Dictionary<string, ITransformStrategy>()
{
{ "Simple URL", new TransformStrategy<SimpleUrlCodeExtractor>() },
{ "Overview", new TransformStrategy<OverviewCodeExtractor>() },
{ "Video List", new TransformStrategy<VideoListCodeExtractor>() },
{ "Video List No MbORKb", new TransformStrategy<VideoListNoMBOrKBAndNoLinksAllowedCodeExtractor>() },
{ "Blue Mountain 2007", new TransformStrategy<BlueMountain2007CodeExtractor>() },
{ "Four Gates", new TransformStrategy<FourGatesCodeExtractor>() },
{ "General", new TransformStrategy<GeneralCodeExtractor>() }
};
public override void DrawForm()
{
// ...
ParentForm.cmboTransformStrategy.DataSource = new BindingSource(strategies, null);
ParentForm.cmboTransformStrategy.DisplayMember = "Key";
ParentForm.cmboTransformStrategy.ValueMember = "Value";
}
public override IEnumerable<string> ProcessHtml(string urlPath)
{
ITransformStrategy transformStrategy = (ITransformStrategy)ParentForm.cmboTransformStrategy.SelectedValue;
// Do some stuff with 'transformStrategy'
}
}
Do you mean something like the following?
public class Strategy
{
private string _name = "default";
public string Name
{
get { return _name; }
set { _name = value; }
}
public Strategy(string name)
{
_name = name;
}
}
Then in form load (you need to have a combo box on that form):
private void Form1_Load(object sender, EventArgs e)
{
List<Strategy> ls = new List<Strategy>();
ls.Add(new Strategy("First"));
ls.Add(new Strategy("Second"));
ls.Add(new Strategy("Third"));
comboBox1.DataSource = ls;
comboBox1.DisplayMember = "Name";
}
Override ToString for your strategy object. After that you can insert your strategy objects directly in the combo box.
public class StrategyObject
{
public override string ToString()
{
return "return the text to display";
}
}
StrategyObject selectedStratObj = comboBox1.SelectedItem as StrategyObject;
I would use the SelectedIndexChanged event on the combobox and select the corresponding dictionary entry
found that, Bind a Dictionary to a ComboBox see below for a working example(at least on the original vb.net code that I wrote)
Vb.net converted into C#, you will have to manage the handle yourself
public class Form1
{
private Dictionary<int, myDic> dict = new Dictionary<int, myDic>();
private void // ERROR: Handles clauses are not supported in C#
ComboBox1_SelectedIndexChanged(System.Object sender, System.EventArgs e)
{
KeyValuePair<int, myDic> curItem = (KeyValuePair<int, myDic>)ComboBox1.SelectedItem;
MessageBox.Show(curItem.Value.myvalue);
}
private void // ERROR: Handles clauses are not supported in C#
Form1_Load(object sender, System.EventArgs e)
{
myDic d = default(myDic);
for (int i = 0; i <= 10; i++) {
d = new myDic();
d.myKey = i.ToString;
d.myvalue = Strings.Chr(65 + i);
dict.Add(d.GetHashCode, d);
}
ComboBox1.DataSource = new BindingSource(dict, null);
ComboBox1.DisplayMember = "value";
ComboBox1.ValueMember = "Key";
}
}
class myDic
{
public string myKey;
public string myvalue;
public override string tostring()
{
return myvalue;
}
}
Here's one of my finest innovations. :) I'm really proud of this little one.
public class Stringable<T>
{
private T _obj;
private Func<T, string> _convertFn;
public Stringable(T obj, Func<T, string> convertFn)
{
_obj = obj;
_convertFn = convertFn;
}
public T GetObj() { return _obj; }
public override string ToString() { return _convertFn(_obj); }
}
This generic class adds ToString() to any class (even a black-box class) and you can define its behavior inside the lambda. Imagine you have a class Person with properties FirstName and LastName. Here's how you would use it to populate Combo box.
_cboPersons.Items.Add(new Stringable<Person>(person,o=>string.Format("{0}, {1}", o.LastName, o.FirstName)));
Then, when combo box item is selected just use this to get the original object from your combo
Person person=(_cboPersons.SelectedItem as Stringable<Person>).GetObj() // Get's person object.

Categories