I have a routine which opens a recordset and builds the Items collection for a combo box. After googling around I found the approach which uses the ComboboxItem class.
public class ComboboxItem
{
public string Text { get; set; }
public object Value { get; set; }
public override string ToString()
{
return Display;
}
}
My code uses this class to Add items to the ComboBox. When I run the app and click the Combobox the correct values are in the list... great! My problem is that when the form loads a record from the database, instead it looking up the appropriate list value which corresponds to the database value, it simply shows the value from the database: eg UK instead of United Kingdom. When I try to save the record, it tries to save "United Kingdom" instead of "UK". So I think the DisplayMember and ValueMember properties need assigning. I assumed that I would need to assign them as "Text" and "Value", but when I do this the Combobox displays a list of identical values. What am I doing wrong please?
Edit: This is a simplified version of what I have put into my ComboBox Class:
public class StandardComboBox : ComboBox
{
protected List<ComboboxItem> DataSourceList = new List<ComboboxItem>();
public bool SetRecordSource(string Criteria)
{
ADODB.Recordset RS = new ADODB.Recordset();
try
{
DataSourceList.Clear();
// Open ADDOB.Recordset RS with the records specified in Criteria
while (RS.EOF == false)
{
ComboboxItem MyComboboxItem = new ComboboxItem();
MyComboboxItem.Value = RS.Fields[0].Value.ToString();
MyComboboxItem.Display = RS.Fields[1].Value.ToString();
DataSourceList.Add(MyComboboxItem);
RS.MoveNext();
}
this.DataSource = DataSourceList;
this.ValueMember = "Value";
this.DisplayMember = "Display";
return true;
}
}
}
First, I think you should name your class better (eg. Country). Then set the name of the property too. Use string as your data type.
public class Country
{
public string ID { get; set; }
public string Name { get; set; }
}
Then you bind the combobox and set the DisplayMember and DisplayValue.
comboBox1.DataSource = listCountry;
comboBox1.DisplayMember = "Name";
comboBox1.ValueMember = "ID";
If you want to take the value, just use SelectedValue.
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show(comboBox1.SelectedValue.ToString());
}
Full source code.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication4
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
var listCountry = new List<Country>() {
new Country() {ID = "UK", Name = "United Kingdom"},
new Country() {ID = "US", Name = "United States of America"},
};
comboBox1.DataSource = listCountry;
comboBox1.DisplayMember = "Name";
comboBox1.ValueMember = "ID";
}
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show(comboBox1.SelectedValue.ToString());
}
}
public class Country
{
public string ID { get; set; }
public string Name { get; set; }
}
}
I've managed to work this out now. I'm from an MsAccess background where for example you just assign a combobox with 'UK' and the combobox displays 'United Kingdom'. In C# it's more complicated. When you want to assign a combobox with a value, you have to use the FindString() method to locate the value you want to display, then assign the SelectedIndex property in order to make it display that value. It's a ball ache, but I can build this logic into my class and not have to think about it again. Thanks for your input. –
Related
public void Fill()
{
cmb1.DataSource = dt;
cmb1.DisplayMember = "Name";
cmb1.ValueMember = "ID";
}
public void Remove()//by Text
{
string selectedItem ="Jack";
cmb1.Items.Remove(selectedItem );
}
public void Remove()//by Value
{
string selectedvalue ="10";
cmb1.Items.RemoveAt(selectedvalue);
}
This Code used but not worked.
Not Remove Using Value or Text.Or Any Other Methods to fill combobox without DataSource.
You can do the following because you are using a data source:
DataTable dt = (DataTable)cmb1.DataSource;
dt.Rows.RemoveAt(cmb1.SelectedIndex);
Try something like this:
class Student {
public int ID{get;set;}
public string Name { get; set; }
// You override this method depending in what you want to show on the comboBox as text
public override string ToString()
{
return Name;
}
}
private void fillComboBox(List<Student> students)
{
// We manually fill the comboBox Items; The displayed text is going to be define by the ToString() method this object has define
students.ForEach(x => cmb1.Items.Add(students));
}
private void button1_Click(object sender, EventArgs e)
{
// We can remove the items by just doing this
cmb1.Items.Remove(cmb1.SelectedItem);
}
So I need to show in a Grid a list of numbers that people enter to help them double check their work. It almost works except it doesn't show the numbers. My setup is simple. I have a textbox, they enter the number, when the add button is clicked its added to a BindingList and then that is used as the datasource for the DataGridView.
So, with some help from this Stackoverflow Post I was able to get this halfway working.
Unfortunately, even though it appears to add a row the Grid each time it does not correctly show the value. It shows the new rows as empty.
Here is my code.
public partial class ManualEntry : Form
{
BindingList<long> ProjectIDs;
public ManualEntry()
{
InitializeComponent();
ProjectIDs = new BindingList<long>();
}
When the add button is clicked, this gets executed.
private void AddButton_Click(object sender, EventArgs e)
{
try
{
long temp = long.Parse(textBox1.Text);
ProjectIDs.Add(temp);
ProjectsGrid.DataSource = ProjectIDs;
textBox1.Text = "";//clear the textbox so they can add a new one.
}
catch//bring up the badinput form
{
BadInput b = new BadInput();
b.Show();
}
}
And so here is the result of adding a few numbers.
If you need any other code from me to help you answer the question, just ask.
You haven't told the DataGridViewColumn what to bind to.
Normally you bind to a public property of the bound data type. In this case your data type is long which does not have an appropriate property to bind to.
Wrap your long in a custom class and expose it as a public property.
public class Data
{
public long Value { get; set; }
}
Bind your column to the Value property. You can do this in the designer, but here is the code:
Column1.DataPropertyName = "Value";
Now instead of long you use Data:
ProjectIDs = new BindingList<Data>();
...
long temp = long.Parse(textBox1.Text);
ProjectIDs.Add(new Data { Value = temp });
The following post discusses this:
DataGridView bound to BindingList does not refresh when value changed
It looks like your data type in the binding list needs to support the INotifyPropertyChanged interface:
http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx
NOTE: Revised - my use of INotifyPropertyChanged was incorrect and also appears not to be needed.
Now this answer is basically just like Igby's - so I think his is the better one :)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
ProjectIDs = new BindingList<AwesomeLong>();
var source = new BindingSource( ProjectIDs, null );
dataGridView1.DataSource = source;
dataGridView1.Columns.Add( new DataGridViewTextBoxColumn() );
}
BindingList<AwesomeLong> ProjectIDs;
private int i = 0;
private void button1_Click( object sender, EventArgs e )
{
i++;
ProjectIDs.Add(new AwesomeLong(i));
}
}
public class AwesomeLong
{
public long LongProperty { get; set; }
public AwesomeLong( long longProperty )
{
LongProperty = longProperty;
}
}
}
I am developing a restaurant application in which a new order will be placed. Itemtype will be in combobox. And based on the selection of combobox value, results should be displayed in DataGridView. For example, if I select "Biryani" Item in combobox, all the Biryani type items should be displayed in DataGridView.
As far as I understand your question, you could probably do this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
namespace WindowsFormsApplication1 {
public partial class Form1 : Form {
public class Selection {
public enum eType { None, Indian, Chinese, Italian, British };
public eType Type { get; private set; }
public string Name { get; private set; }
public Selection(eType xType, string xName) {
Type = xType;
Name = xName;
} //
} // class
private List<Selection> _AllMeals = new List<Selection>();
public Form1() {
InitializeComponent();
comboBox1.DataSource = Enum.GetValues(typeof(Selection.eType)).Cast<Selection.eType>();
comboBox1.SelectedItem = Selection.eType.None;
Selection s1 = new Selection(Selection.eType.Chinese, "tasty Wan Tan soup");
Selection s2 = new Selection(Selection.eType.Chinese, "yummy Spring Rolls");
Selection s3 = new Selection(Selection.eType.Indian, "extreme spicy");
Selection s4 = new Selection(Selection.eType.Indian, "deadly spicy");
Selection s5 = new Selection(Selection.eType.Italian, "great Tortellini");
Selection s6 = new Selection(Selection.eType.Italian, "large Pizza");
Selection s7 = new Selection(Selection.eType.British, "fatty Fish and Chips");
_AllMeals.AddRange(new Selection[] { s1, s2, s3, s4, s5, s6, s7 });
dataGridView1.DataSource = _AllMeals;
} //
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) {
object o = comboBox1.SelectedItem;
Selection.eType lFilter = (Selection.eType)o;
var lOptions = (from x in _AllMeals
where x.Type == lFilter
select x).ToArray();
dataGridView1.AutoGenerateColumns = true;
dataGridView1.DataSource = lOptions;
dataGridView1.Invalidate();
} //
} // class
} // namespace
Visit my blog at www.ohta.de
As i can read that you are talking about DAtaGridView and ComboBox, you must be using Windows Forms. So what you ca do is call SelectedIndexChanged event of ComboBox, then you can bind the DataGridView. e.g
private void ComboBox1_SelectedIndexChanged(object sender, System.EventArgs e)
{
ComboBox combo = sender as ComboBox;
if(combo.SelectedIndex >=0)
{
int itemId=Convert.ToInt32(combo.SelectedValue);
datagridview1.DataSource = somFunction(itemId);
}
}
For my windows forms application I tried to retrieve the selected string from a listBox and i wanted it to compare to a set string so that, in the event of the comparison returning true, i can set the next listBox to have specific, selection-related values.
namespace PhysCalc
{
public class Selectors
{
public static string[] topicContents = new string[] { "MECHANICS", "THEORY_OF_RELATIVITY" };
public static string[] VarItemsMechanics = new string[] { "Test", "Wavelength" };
public static void SetVarBox()
{
PhysCalc.Topic.DataSource = topicContents;
if PhysCalc.Topic.Items[PhysCalc.Topic.SelectedIndex].ToString() == "MECHANICS")
{
PhysCalc.Var.DataSource = VarItemsMechanics;
}
}
}
}
But somehow when i select "MECHANICS" in the listBox(in the code above named 'Topic'), the 2nd listBox(above named 'Var') just stays empty
any help would be very appreciated
I think you need to set the DisplayMember and ValueMember properties on the Var list control when using the DataSource.
If the DataSource is an object then DisplayMember is the object member it will use as the text display (which in your case is currently blank), and ValueMember is used to determine the SelectedValue property of the list control which is useful to bind against.
For example if your VarItemsMechanics is populated with the following class:
public class Mechanic
{
public int ID { get; set; }
public string Name { get; set; }
}
Then you probably want to set the DisplayMember to "Name" and you might want to set the ValueMember to "ID" (subjective).
Try changing
if (PhysCalc.Topic.GetItemText(PhysCalc.Topic.SelectedItem) == "MECHANICS")
to this:
if (PhysCalc.Topic.Items[PhysCalc.Topic.SelectedIndex].ToString() == "MECHANICS")
1- Bind your First List named "Topic" in the form_load Event
2- in the SelectedIndexChanged Event of your First List do your checks about the selected Item
and Fill the Second List
Here is the Complete Code and it works fine for me
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public static string[] topicContents = new string[] { "MECHANICS", "THEORY_OF_RELATIVITY" };
public static string[] VarItemsMechanics = new string[] { "Test", "Wavelength" };
private void Form1_Load(object sender, EventArgs e)
{
listBox1.DataSource = topicContents;
}
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
string curItem = listBox1.SelectedItem.ToString();
switch (curItem)
{
case "MECHANICS":
listBox2.DataSource = VarItemsMechanics;
break;
}
}
}
}
I've always understood that DisplayMember and ValueMember are only supposed to be used when databinding a ComboBox using its DataSource property.
But in some code I'm maintaing I've noticed that using a ComboBox' DisplayMember property does work without databinding. Setting the property determines what is shown in the combobox. Setting ValueMember does not seem to work though (it does not set SelectedValue).
My question is: is it safe to use this behavior? Or is there a risk the behavior may change in upcoming versions of .NET?
I know you'd normally override the ToString method. In the real code, the MyType class is not as simple as in my example. I'm not sure if it would be safe to override its ToString method.
A small sample to show this behavior.
using System;
using System.Windows.Forms;
internal class Program {
public class MyType {
public string MyText { get; set; }
public string MyValue { get; set; }
}
public class MyForm : Form {
private readonly ComboBox _myComboBox;
public MyForm() {
_myComboBox = new ComboBox {DisplayMember = "MyText", ValueMember = "MyValue"};
_myComboBox.Items.Add(new MyType {MyText = "First item", MyValue = "1"});
_myComboBox.Items.Add(new MyType {MyText = "Second item", MyValue = "2"});
_myComboBox.SelectedIndexChanged += _myComboBox_SelectedIndexChanged;
Controls.Add(_myComboBox);
}
private void _myComboBox_SelectedIndexChanged(object sender, EventArgs e) {
var cb = (ComboBox) sender;
System.Diagnostics.Debug.WriteLine(
"Index: {0}, SelectedValue: {1}", cb.SelectedIndex, cb.SelectedValue);
}
}
private static void Main() {
Application.Run(new MyForm());
}
}