How do you bind a data field value to a combobox index? - c#

This may have been already asked but I can't seem to find this specific question, so here goes...
I have a form in C# where every textbox is bound to a field in a row. Rows can be cycled through by some buttons on the bottom but all the data displayed at a time in the from is from one row. Any changes that are made get updated back to the database when the user clicks "update"
One field (class) is an enumeration (0,1,2) where only the value is stored in the database, but doesn't mean much to the user. I was asked to make this more obvious to the user, so I decided to go with a dropdown style combo box. Since the database didn't have any reference to what the values meant, I decided to use the DataBindings instead of DataSource so I could just use the index as the data bind, but it seems that SelectedItem or Value are not the way to do this.
Here is my goal:
1 exists in database, so "B" is selected in combo box.
User selects "C" and updates the database, 2 is now stored in the database.
Any thoughts on what I need to get this working?

I assume you have a BindingSource on your form to bind to the data. You can bind the SelectedIndex property of the ComboBox as follows:
comboBox.DataBindings.Add("SelectedIndex", bindingSource, "PropertyInTheDataSource");

Actually I was able to bind it to a custom Object. It's a little too much work for such a simple task. But you have complete control on Display/Value pairs. Anyway, I thought I'd share and you decide:
Create a new class (say CustomItem) with 2 fields:
Public int Value{get;set;}
public string Title {get;set;}
Then in you form:
var item1 = new CustomItem() { Title = "A", Value = 10 };
var item2 = new CustomItem() { Title = "B", Value = 20 };
var item3 = new CustomItem() { Title = "C", Value = 30 };
var lst = new List<CustomItem>();
lst.Add(item1);
lst.Add(item2);
lst.Add(item3);
comboBox1.DataSource = lst;
comboBox1.DisplayMember = "Title";
comboBox1.ValueMember = "Value";
Now You have a databound combobox in case you don't have BndingSource in your form.
Just remember to define your class's Title and Value as properties otherwise it wouldn't work.

Related

ComboBoxes are linked (and that is bad)

I am doing simple WinForms application, and I am facing some strange problem.
My form:
It is as easy as it can be: 3 comboboxes, and two buttons - OK and Cancel.
View:
private void applyOrderButton_Click(object sender, EventArgs e)
{
List<string> testList = new List<string>()
{
"A",
"B",
"C"
};
comboBox1st.DataSource = testList;
comboBox2nd.DataSource = testList;
comboBox3rd.DataSource = testList;
comboBox1st.SelectedIndex = 2;
comboBox2nd.SelectedIndex = 1;
comboBox3rd.SelectedIndex = 0;
//Presenter.DoTest();
}
What happens after caling method applyOrderButton_Click() (it happens after Ok button is clicked) all of my comboBoxes change selected position. However, each of those comboBoxes have the same selected index - in this particular case it will be "A".
Then I change change comboBox selectedIndex using my cursour (for example I choose 3rd comboBox to show "C") the change is performed for all three comboBoxes. What I am doing wrong?
You are running across something that is present in the background of WinForms called the "CurrencyManager".
Its job is to synchronize the "current record" across all bindable controls that refer to the same data source.
For instance, if you had added a label and bound it to the same list, and bound it so that it shows a property of one of the objects, it would always show the property value of the same object you had selected in the combobox.
One bonus of this is that you could easily add a form that edits a list of objects, binding textboxes and such to the properties of one of the objects and adding a navigator that allows you to move to the next or previous row. You would not have to manually ensure all textboxes refer to the correct object, the CurrencyManager would do all this for you.
However, in your case, since you bound the same data source to all three comboboxes, the CurrencyManager will ensure all three select the same row. If you select a new row in one of the comboboxes, the CurrencyManager will go and fix all the others to refer to the same row.
You can fix this in various ways:
You can override the binding context for each combobox:
comboBox2nd.BindingContext = new BindingContext();
comboBox3rd.BindingContext = new BindingContext();
Note that if you go this route you need to do this before assigning the SelectedIndex or SelectedItem properties, otherwise the CurrencyManager will have updated the other two comboboxes before you assigned new BindingContexts.
You can assign distinct data sources to each combobox:
combobox2nd.DataSource = testList.ToList();
combobox3rd.DataSource = testList.ToList();
Just assign new context to other ComboBoxes like that:
List<string> testList = new List<string>()
{
"A",
"B",
"C"
};
comboBox1st.DataSource = testList;
comboBox2nd.BindingContext = new BindingContext();
comboBox2nd.DataSource = testList;
comboBox3rd.BindingContext = new BindingContext();
comboBox3rd.DataSource = testList;
comboBox1st.SelectedIndex = 2;
comboBox2nd.SelectedIndex = 1;
comboBox3rd.SelectedIndex = 0;
The CurrencyManager is used to keep data-bound controls synchronized with each other (showing data from the same record). The CurrencyManager object does this by managing a collection of the bound data supplied by a data source. For each data source associated with a Windows Form, the form maintains at least one CurrencyManager. Because there may be more than one data source associated with a form, the BindingContext object manages all of the CurrencyManager objects for any particular form. More broadly, all container controls have at least one BindingContext object to manage their CurrencyManagers.

Add 2 or more field to value member of C# coding

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());
}

Combo Boxes With Multiple Columns

I've read that combo boxes cannot have multiple columns. Which leaves me a bit stuck since what I want to do is display one field from a table, but return the corresponding value from a second field in the same table i.e.
I'd like to show CustomerNames in the combo box, but when the user selects a name, the CustomerID field is returned instead. Whats the best work around for this?
Best way is to use ComboBoxes DisplayMember and ValueMember properties
set the ComboBox.DisplayMember to the property you want to display. Use ValueMember for property you want to return. Then you can use the ComboBox.SelectedValue to get the current/selected ValueMember
You don't need multiple columns to implement it.
class Member
{
public string Name{get;set;}
public string Address{get;set;}
public int ID{get;set;}
public string Description
{
get
{
return string.Format("{0}, {1}", Name, Address);
}
}
}
var members = new []
{
new Member(){ID = 1, Name = "John", Address = "Addr 1"},
new Member(){ID = 2, Name = "Mary", Address = "Addr 2"}
};
m_ComboBox.DataSource = members;
m_ComboBox.DisplayMember = "Description"
m_ComboBox.ValueMember = "ID";
now you can access seleceted ID
var selectedID = m_ComboBox.CelectedValue();
The value of the ComboBoxItem does not have to be the same as the Text, consider using the ID as the value.
You can achieve the desired behaviour by setting the DisplayMember and ValueMember properties of the ComboBox to "CustomerName" and "CustomerID" respectively.
Take a look at the ValueMember property. You should set this to CustomerID. After you bind to your combobox, the actual field displayed to the user will be the CustomerName, but when you want to get the value of 'CustomerName', it will return the CustomerID.
When you want to get the value of the combobox, simply reference the SelectedValue.
If you are adamant about displaying both of these in the combobox, there are some hackish ways of doing this but I would recommend reviewing your requirements again and seeing if it is absolutely necessary.
Alternatively, you can define KeyValuePair objects with your intended Ids and text fields. Feed them to the combo, since its Items property is a collection of objects. Then, for retrieval use a cast like
var x = (KeyValuePair)combo.Items[0];
and then acces then Key and Value properties of x.
You can use Tag property of ComboBoxItem to store the value.

How to set selected value from Combobox?

I use combobox in c# windows form. I bound the item list as below:
var employmentStatus = new BindingList<KeyValuePair<string, string>>();
employmentStatus.Add(new KeyValuePair<string, string>("0", "[Select Status]"));
employmentStatus.Add(new KeyValuePair<string, string>("1", "Contract"));
employmentStatus.Add(new KeyValuePair<string, string>("2", "Part Time"));
employmentStatus.Add(new KeyValuePair<string, string>("3", "Permanent"));
employmentStatus.Add(new KeyValuePair<string, string>("4", "Probation"));
employmentStatus.Add(new KeyValuePair<string, string>("5", "Other"));
cmbEmployeeStatus.DataSource = employmentStatus;
cmbEmployeeStatus.ValueMember = "Key";
cmbEmployeeStatus.DisplayMember = "Value";
cmbEmployeeStatus.SelectedIndex = 0;
I save the selected value in database eg.1 or 2. Now I want to set selected value from database item like:
cmbEmployeeStatus.SelectedValue =employee.employmentstatus;
But combobox not selected with value. How can I do that?
Try this one.
cmbEmployeeStatus.SelectedIndex = cmbEmployeeStatus.FindString(employee.employmentstatus);
In order to do the database style ComboBoxes manually trying to setup a relationship between a number (internal) and some text (visible), I've found you have to:
Store you items in a list (You are close - except the string,string - need int,string)
DataSource property to the list (You are good)
DataMember,DataValue (You are good)
Load default value (You are good)
Put in value from database (Your question)
Get value to put back in database (Your next question)
First things first. Change your KeyValuePair to so it looks like:
(0,"Select")
(1,"Option 1")
Now, when you run your sql "Select empstatus from employees where blah" and get back an integer, you need to set the combobox without wasting a bunch of time.
Simply: *** SelectedVALUE - not Item ****
cmbEmployeeStatus.SelectedValue = 3; //or
cmbEmployeeStatus.SelectedValue = intResultFromQuery;
This will work whether you have manually loaded the combobox with code values, as you did, or if you load the comboBox from a query.
If your foreign keys are integers, (which for what I do, they all are), life is easy. After the user makes the change to the comboBox, the value you will store in the database is SelectedValue. (Cast to int as needed.)
Here is my code to set the ComboBox to the value from the database:
if (t is DBInt) //Typical for ComboBox stuff
{
cb.SelectedValue = ((DBInt)t).value;
}
And to retrieve:
((DBInt)t).value = (int) cb.SelectedValue;
DBInt is a wrapper for an Integer, but this is part of my ORM that gives me manual control over databinding, and reduces code errors.
Why did I answer this so late? I was struggling with this also, as there seems to be no good info on the web about how to do this. I figured it out, and thought I'd be nice and post it for someone else to see.
In windows Appliation
we use like this
DDLChangeImpact.SelectedIndex = DDLChangeImpact.FindStringExact(ds.Tables[0].Rows[0]["tmchgimp"].ToString());
DDLRequestType.SelectedIndex = DDLRequestType.FindStringExact(ds.Tables[0].Rows[0]["rmtype"].ToString());
Use the SelectedIndex property for the respective employee status in the combo box.
Below will work in your case.
cmbEmployeeStatus.SelectedItem =employee.employmentstatus;
When you set the SelectedItem property to an object, the ComboBox attempts to make that object the currently selected one in the list. If the object is found in the list, it is displayed in the edit portion of the ComboBox and the SelectedIndex property is set to the corresponding index. If the object does not exist in the list, the SelectedIndex property is left at its current value.
EDIT
I think setting the Selected Item as below is incorrect in your case.
cmbEmployeeStatus.SelectedItem =**employee.employmentstatus**;
Like below
var toBeSet = new KeyValuePair<string, string>("1", "Contract");
cmbEmployeeStatus.SelectedItem = toBeSet;
You should assign the correct name value pair.
cmbEmployeeStatus.Text = "text"
I suspect something is not right when you are saving to the db. Do i understand your steps as:
populate and bind
user selects and item, hit and save.. then you save in the db
now if you select another item it won't select?
got more code, especially when saving? where in your code are initializing and populating the bindinglist
A possible solution:
cmbEmployeeStatus.SelectedValue = cmbEmployeeStatus.Items.FindByText("text").Value;
try this
combobox.SelectedIndex = BindingSource.Item(9) where "9 = colum name 9 from table"
To set value in the ComboBox
cmbEmployeeStatus.Text="Something";
Try this:
KeyValuePair<string, string> pair = (KeyValuePair<string,string>)this.ComboBox.SelectedItem;

How do I get the combobox value?

I usually do web programming but have a requirement for a windows form in this project I'm working on now.
I'm using SubSonic to get a list of jobs and load a combobox:
JobCollection jobs = new JobCollection().Load();
cboJobs.DisplayMember = "Name";
cboJobs.ValueMember = "Id";
cboJobs.DataSource = jobs;
When the user selects an item and clicks the search button I need to query the database using the job "Id" field.
TransactionCollection transactions = new TransactionCollection();
if (!String.IsNullOrEmpty(txtTransactionId.Text))
{
transactions.Where("id", txtTransactionId.Text);
}
else
{
transactions.Where("raw_data", Comparison.Like, "%" + txtFind.Text + "%");
}
transactions.Where("job_id", Convert.ToInt32(cboJobs.SelectedItem));
transactions.Load();
The line that is having the problem is the one that goes "Convert.ToInt32(cboJobs.SelectedItem)".
How do I get the job id versus the name?
You might want to look at the SelectedValue property of your combobox. You set the ValueMember to the ID, so the SelectedValue should contain the correct value.
You have already gotten (a good) answer, but I thought it might be in place to point this out anyway: in your application's combo box, each item will actually be a full Job object, not only a string representation of one. So the SelectedItem property will return the Job object that is currently selected in the ComboBox. You can access any of its members simply by casting it to Job:
Job currentJob = cboJobs.SelectedItem as Job;
if (currentJob != null)
{
// here you can access currentJob.Name, currentJob.Id or any other member
}

Categories