asked on
C# populate multiple values from combo box?
I am trying to populate three text fields:
txtID, txtCodes and TxtSuffix
I have created a class and the combo box.
How do I finish this so all three text fields will populate?
==============================================================
private class Harmonization
{
public string Id { get; set; }
public string Code { get; set; }
public string Suffix { get; set; }
}
==============================================================
var dtharmon = new DataTable();
_cmdText = "SELECT [ID]" +
",[Codes]" +
",[Suffix] " +
"FROM[MERCH].[dbo].[AAA_Harmonization_Codes] " +
"ORDER BY [Suffix]";
using (var daharmon = new SqlDataAdapter(_cmdText, _gpconn))
{
daharmon.Fill(dtharmon);
cboHarmCode.DataSource = dtharmon;
cboHarmCode.DisplayMember = "Suffix";
cboHarmCode.ValueMember = "Suffix";
cboHarmCode.SelectedIndex = 0;
}
ASKER
var selectedDataRow = (DataRow)cboHarmCode.Selec
"Unable to obtain harmonization code?
==========================
private void cboHarmCode_SelectedIndexC
{
var selectedDataRow = (DataRow)cboHarmCode.Selec
var x = new Harmonization()
{
Id = (string)selectedDataRow["I
Code = (string)selectedDataRow["C
Suffix = (string)selectedDataRow["S
};
txtID.Text = x.Id;
txtCode.Text = x.Code;
txtSuffix.Text = x.Suffix;
Is "Unable to obtain harmonization code" the error you're getting?
If so, that is a custom error message, so can you provide the base error / exception?
ASKER
ASKER
if (_gpconn.State == ConnectionState.Open)
{
var dtharmon = new DataTable();
_cmdText = "SELECT [ID],[CODES],[SUFFIX] " +
"FROM [dbo].[AAA_Harmonization_C
"ORDER BY [SUFFIX]";
using (var daharmon = new SqlDataAdapter(_cmdText, _gpconn))
{
daharmon.Fill(dtharmon);
cboHarmCode.DataSource = dtharmon;
cboHarmCode.DisplayMember = "SUFFIX";
cboHarmCode.ValueMember = "SUFFIX";
cboHarmCode.SelectedIndex = 0;
}
}
Sorry I made a mistake.
It should be (DataRowView), not (DataRow). There is an intermediate view object there.
var selectedDataRow = (DataRowView)cboHarmCode.SelectedItem;
@Kyle - there is no problem setting the DisplayMember or ValueMember (although the ValueMember isn't really used here).
Time for bed, lol.
Also, while there's no particular problem with using a DataTable as the data source, it can -sometimes- give you a little more flexibility to use a List<> of an object like List<Harmonization> as the data source.
For what it's worth, data binding would work well here.
The way I would approach it overall:
First, add a method to convert the DataTable into a List<Harmonization>:
public class Harmonization
{
public string Id { get; set; }
public string Code { get; set; }
public string Suffix { get; set; }
public static List<Harmonization> FromDataTable(DataTable dt)
{
var list = new List<Harmonization>();
foreach(DataRow dr in dt.Rows)
{
list.Add(new Harmonization()
{
Id = (string)dr["ID"],
Code = (string)dr["Codes"],
Suffix = (string)dr["Suffix"]
});
}
return list;
}
}
Next, add a property to your class to hold the selected Harmonization object.
public Harmonization selectedHarmonization { get; set; }
Next, call this method to convert the DataTable to the List<Harmonization> and use that List as your data source, and also add the binding so it updates selectedHarmonization automatically.
using (var daharmon = new SqlDataAdapter(_cmdText, _gpconn))
{
daharmon.Fill(dtharmon);
var harmonizations = Harmonization.FromDataTable(dtharmon);
cboHarmCode.DataSource = harmonizations;
cboHarmCode.DisplayMember = "Suffix";
cboHarmCode.DataBindings.Add(new Binding("SelectedItem", this, "selectedHarmonization"));
cboHarmCode.SelectedIndexChanged += (object sender, EventArgs e) => { cboHarmCode.DataBindings["SelectedItem"].WriteValue(); };
cboHarmCode.SelectedIndex = 0;
}
Now from here, you can just add the 3 data bindings to your text fields:
txtID.DataBindings.Add(new Binding("Text", cboHarmCode, "SelectedItem.Id"));
txtCode.DataBindings.Add(new Binding("Text", cboHarmCode, "SelectedItem.Code"));
txtSuffix.DataBindings.Add(new Binding("Text", cboHarmCode, "SelectedItem.Suffix"));
With those changes, as soon as you change the combo box selection, it should:
1. Update the 3 textbox values automatically.
2. Update the "selectedHarmonization" object, in case you want to reference it later.
ASKER
I have attached the updated code.
frmHarmonization.zip
Your error message screenshots are coming through really small and can't be read. Can you share the text?
ASKER
ASKER
ASKER
I complains about this line.
var harmonizations = Harmonization.FromDataTabl
Error-Harmonization3.png
ASKER
Debug.png
On a side note, Data Binding is 2-way by default. This means that if someone selected Suffix "abc" and the 3 textboxes populate and then someone changes a value in that textbox, then the new value from the texbox will update the Harmonization object in memory.
This is often a desired effect with binding because it allows you to essentially set up a data entry form that can update the backend without having to write tons of repetitive "ok now go and update this field again" code. But if you just want the data binding to be one-way so that the combobox changes the textboxes but never the other way around, you can do it in one of three ways:
1. If the users should never change the textboxes at all, then just make the textboxes read-only.
2. If the users should be able to -temporarily- change the textboxes but the new value doesn't go back to the original Harmonization object, then just change the Harmonization object properties to { get; private set; } like this:
public class Harmonization
{
public string Id { get; private set; }
public string Code { get; private set; }
public string Suffix { get; private set; }
3. Or you can add an extra statement to each of the textbox data bindings to specify that the data source (the original Harmonization object that was selected in the combo box) should never be updated by the textboxes:
txtID.DataBindings.Add(new Binding("Text", cboHarmCode, "SelectedItem.Id")
{
DataSourceUpdateMode = DataSourceUpdateMode.Never
});
txtCode.DataBindings.Add(new Binding("Text", cboHarmCode, "SelectedItem.Code")
{
DataSourceUpdateMode = DataSourceUpdateMode.Never
});
txtSuffix.DataBindings.Add(new Binding("Text", cboHarmCode, "SelectedItem.Suffix")
{
DataSourceUpdateMode = DataSourceUpdateMode.Never
});
Usually #1 is easier AND it's a better user experience unless you WANT the user to be able to temporarily modify the textboxes.
ASKER
In the ERP solution there is a screen for items. I am grabbing the item number and then opening a window that will allow the user to assign these other values and then commit these values to a table in SQL. This error is occurring on a sub form that would allow the user to change values on any of these three values. Changing these values would be rare but there is also a possibility that may want to add a new harmonization code.
I have attached the latest code.
frmHarmonization.zip
Can you adjust the exception so it shows the actual error message? Right now you have:
string eMsg = "frmHarmonization - 001 - Error : Unable to obtain harmonization codes";
eMsg += "\n" + ex.StackTrace;
But that doesn't tell you what the error is. You need to include ex.Message in there somewhere.
Also, are the 3 fields in the database all strings? I had assumed so, since your properties were strings. But if your ID was an integer, for example, that would result in a casting error.
You'd have to adjust the property type and the cast. For example, if the Id property WAS an integer, you'd change:
public string Id { get; set; }
to:
public int Id { get; set; }
and you'd change the cast from:
Id = (string)dr["ID"],
to:
Id = (int)dr["ID"],
ASKER
There should be a property called SelectedItem on the combo box. It is intended to be able to hold many different types of objects, so it's typed as "object" but in your example, you're binding to a DataTable, so when you select an item in the ComboBox, then the SelectedItem will point to the corresponding DataRow object.
So when you need to fill your Harmonization object, just cast SelectedItem back to the DataRow type, and then access the fields in that row:
Open in new window