I want to use a C# Windows Forms combo box to select the value of an enum:
this.comboBoxColor.DataSource = System.Enum.GetValues(typeof(System.Drawing.KnownColor));
But when I put this in the InitializeComponent, it replaces this line with a static assignment of an array with all items in the enum. It does this twice, once for the Datasource, and once for the Items property.
But these things don't work together. When having a bound DataSource, adding items to the Items list causes an error and when doin it the other way around assigning the SelectedValue property doesn't work any more.
I've tried using a separate method to do this outside the InitializeComponent method. And simply setting the DataSource as above in the separate method produces the following error:
System.InvalidOperationException: 'Can't set the SelectedValue in a ListControl with an empty ValueMember.'
Edit: Microsoft says using a simple array as a data source should be possible: https://msdn.microsoft.com/nl-nl/library/x8160f6f(v=vs.110).aspx
It's possible to specify the data source in the designer, but there it only allows selecting classes. What must a class implement to make that work?
You can write a simple method that transforms your enum to a datatable and then use the result of the method as a DataSource with a pair of well known names for the ValueMember and DisplayMember properties of the combo
public DataTable CreateTableFromEnum(Type t)
{
DataTable dt = new DataTable();
if (t.IsEnum)
{
dt.Columns.Add("key", t);
dt.Columns.Add("text", typeof(string));
foreach(var v in Enum.GetValues(t))
dt.Rows.Add(v, v.ToString());
}
return dt;
}
and call it with
var colors = CreateTableFromEnum(typeof(KnownColor));
cbo.ValueMember = "key";
cbo.DisplayMember = "text";
cbo.DataSource = colors;
Now when you look at the selected value you will get the numeric value of the color selected
Related
Here is the thing I add manually few DataRow's to this.listBox1.Items and set in WinForms Designer the DisplayMember to column name but all I get displayed later is a list of type's name (System.Data...) .
How to solve this issue?
CODE:
list1.ForEach(x => this.listBox1.Items.Add(x)); //x is DataRow from a filled DataTable
The DisplayMember and ValueMember are applicable only when you use data binding (ListBox.DataSource). They work either with real properties, which can be retrieved by reflection, or via the .NET component model and the ICustomTypeDescriptor interface.
If you bind a DataTable directly, the GetEnumerator method and the IList implementation returns always DataRowView instances instead of DataRows. DataRowView implements the ICustomTypeDescriptor where the DisplayName can refer a column name.
So if you want to add some custom filtered list, I suggest you to create one from whatever source. For example:
listBox1.DisplayMember = "Name";
listBox1.ValueMember = "Value";
var list = Enumerable.Range(1, 10).Select(i => new {Name = i.ToString(), Value = i}).ToList();
listBox1.DataSource = list;
If Name property exists, you will see its value; otherwise, you will see the ToString of the items.
However, if you add the items programmatically (ListBox.Items), these properties are ignored and always the ToString of the items will be used.
Specify the column name you want to add to your list box:
list1.ForEach(x => this.listBox1.Items.Add(x["column_name"]));
This may be a very simple question but I realized I could not get it work.
I have a Winform combo box with datasource as a List<int>
combo.DataSource = intList;
What do I put for .DisplayMember and .ValueMember in order to simply have a list of integer values? Not setting them will display nothing.
I have worked with other List<myObj> in which DisplayMember and ValueMember are myObj's properties. How about simple data type like int, string?
When retrieving the selected item, one could simply cast (int)(combo.SelectedItem) or have to go through the property corresponding to ValueMember?
The problem does not occur because you have a list of integers, it probably occurs because you add items to the list after assigning it to the .DataSource property. List does not have a mechanism to notify its container when items are added to or removed from it.
Either add items to the list before assigning it to the .DataSource property, or use a wrapper like BindingSource as Krishnraj Rana suggested.
Here BindingSource comes into picture. You can use it like this.
BindingSource bSource = new BindingSource();
bSource.DataSource = new List<int> { 1, 2, 3 };
combo.DataSource = bSource;
Though you can set datasource of combobox directly with list. like this -
combo.DataSource = intList;
This also works perfectly fine.
You can add items from list using foreach like this.
foreach (var v in intList)
{
comboBox1.Items.Add(v.ToString());
}
I have table with 4 primary key fields. I load that in to drop down list in my WinForm application created by using C#.
On the TextChanged event of drop down list I have certain TextBox and I want to fill the information recived by the table for the certain field I selected by the drop down list.
So as I say the table having 4 fields. Can I get those all 4 fields into value member from the data set, or could you please tell me whether is that not possible?
Thank you.
Datatable dt=dba.getName();
cmb_name.ValueMember="id";
cmb_name.DisplayMember="name";
cmb_name.DataSource=dt;
this is normal format.. but i have more key fields.. so i need to add more key fields..
You can use DataSource property to bind your source data to the ComboBox (e.g. a List of Entities, or a DataTable, etc), and then set the DisplayMember property of the ComboBox to the (string) name of the field you want to display.
After the user has selected an Item, you can then cast the SelectedItem back to the original row data type (Entity, DataRow, etc - it will still be the same type as you put in), and then you can retrieve your 4 composite keys to the original item.
This way you avoid the SelectedValue problem entirely.
Edit:
Populate as follows:
cmb_name.DisplayMember = "name";
cmb_name.DataSource = dt;
// Ignore ValueMember and Selected Value entirely
When you want to retrieve the selected item
var selectedRow = (cmb_name.SelectedItem as DataRowView );
Now you can retrieve the 4 values of your PK, e.g. selectedRow["field1"], selectedRow["field2"], selectedRow["field3"] etc
If however you mean that you want to DISPLAY 4 columns to the user (i.e. nothing to do with your Table Key), then see here How do I bind a ComboBox so the displaymember is concat of 2 fields of source datatable?
cmb_name.DisplayMember = "name";
cmb_name.DataSource = dt;
DataRowView selectedRow = (cmb_name.SelectedItem as DataRowView );
The result will be here:
MessageBox.Show(selectedRow.Row[0].ToString());
MessageBox.Show(selectedRow.Row[1].ToString());
MessageBox.Show(selectedRow.Row[2].ToString());
MessageBox.Show(selectedRow.Row[3].ToString());
.....
If you want to get some data from a ComboBox in to a List you can use something like this
List<string> ListOfComboData = new List<string>();
ListOfComboData = yourComboBox.Items.OfType<string>().ToList<string>();
I have no real idea if this is what you mean as the question is very poorly structured. I hope this helps...
Edit: To put the selected text in to some TextBox use
yourTextBox.Text = youComboBox.Text;
in the SelectedIndexChanged event of your ComboBox.
You could follow the approach here with the following class:
public class ComboBoxItem
{
public string Text { get; set; }
public object[] PrimaryKey { get; set; }
}
private void Test()
{
ComboboxItem item = new ComboboxItem();
item.Text = "Item text1";
item.PrimaryKey = new object[] { primaryKey1, primaryKey2, primaryKey3, primaryKey4};
comboBox1.Items.Add(item);
comboBox1.SelectedIndex = 0;
MessageBox.Show((comboBox1.SelectedItem as ComboboxItem).Value.ToString());
}
I have a gridControl who's data source is a List.
Each item in List is made out of three fields.
And I have 3 columns in the gridControl.
when I programatically insert values into the gridview it does not appear.
Here is my code.
public Company_Selection()
{
InitializeComponent();
companies = new List<DataLibrary.Companies>();
gridControl1.DataSource = companies;
}
internal void load_all_companies(List<DataLibrary.Companies> other)
{
for (int i = 0; i < other.Count; i++)
{
companies.Add(other[i]);
gridView1.SetRowCellValue( i, "Id", other[i].id);
gridView1.SetRowCellValue( i, "Company", other[i].name);
gridView1.SetRowCellValue(i, "Description", other[i].description);
gridView1.RefreshData();
gridControl1.RefreshDataSource();
}
}
Any ideas about what's wrong ?
The thing is you should not work with cells directly. Your 'companies' list should be enclosed in BindingList. All programmatical changes are done at object, not grid level. So, setting datasource becomes
gridControl1.DataSource = new BindingList<DataLibrary.Companies>(companies);
This will take care of presentation, changes, additions and deletions of objects within list. The columns will be created automatically if your gridView does not contain any and AutoPopulateColumns is true. You might want to setup columns in gridView using Designer. Don't forget so set Field property to Property name of underlying object.
You correcly set the datasource property, but you have also to bind the datasource to the control by using the DataBind method like this
gridControl1.DataSource = companies;
gridControl1.DataBind();
I think you for get to write DataBind method
gridControl1.DataBind();
so you code will be
companies = new List<DataLibrary.Companies>();
gridControl1.DataSource = companies;
gridControl1.DataBind();
GridView.DataBind Method
: Binds the data source to the GridView control.
Use the DataBind method to bind data from a data source to the GridView control. This method resolves all data-binding expressions in the active template of the control.
I believe the cause of the issue is that you are using fieldnames like "Id","Company", "Description" but the grid is mapped on "id","name","description" fieldnames:
gridView1.SetRowCellValue( i, "Id", other[i].id);
gridView1.SetRowCellValue( i, "Company", other[i].name);
gridView1.SetRowCellValue(i, "Description", other[i].description);
Also passing row cell values directly to a view and refreshing the grid after appending every record is very redundant. The single RefreshDataSource method call after data loading is only enough:
internal void load_all_companies(List<DataLibrary.Companies> other) {
for(int i = 0; i < other.Count; i++)
companies.Add(other[i]);
gridControl1.RefreshDataSource();
}
Actually I need to set the value member of combobox using Foreach loop
My code goes like this.
foreach(DataRow row in dsTable.Tables["mytable"].Rows)
{
combobox1.Items.Add(row["my column"]);
}
how do i set value member on it?
Here is the definition and some examples of combobox use.
msdn combobox link
Basically a combobox accepts "objects" so u could add any kind of items in it.
Hopes it helps.
You're not binding a DataSource so basically there's no point in setting the ValueMember property.
You should do this instead of the loop:
combobox1.DataSource = dsTable.Tables["mytable"];
combobox1.ValueMember = "MyValueColum";
combobox1.DisplayMember = "MyDisplayColumn";