Reputation: 305
I have a dropdown list on my windows form application that holds the manufacturer's names. Upon editing a given record, I want the user to be able to edit (change) the manufacturer as well. The rest of values are working fine and I can easily assign them to the text boxes where they will be edited and stored in the database again.
I have queried the dropdown list item (the manufacturer name that needs to be edited) from the database and now I want to show it as the selected item on the dropdown list. I used the following code to query a particular manufacturer based on id from the database and assign it to a string variable, manufacturerName
.
DataTable dtMName = Products.SelectByManufacturerId(manufacturerId);
if (dtMName.Rows.Count > 0)
{
foreach (DataRow item in dtMName.Rows)
{
string manufacturerName = item[0].ToString();
}
}
Upon debugging this piece of code, the string manfuacturerName
hold the exact manufacturer name that I want to change in the dropdown list. Now, I want to mark this particular item as the selected item in the dropdown list. I want to pass it to the list so that it can select this particular manufacturer in the list.
So far, I have tried the following code but it is not working.
childEditProduct.cmbManufacturer.SelectedIndex = childEditProduct.cmbManufacturer.FindString(manufacturerName);
Note: I have marked the first item as the selectedIndex on childEditProduct form load. I have commented that code as well but nothing works. Is there any issue in my code or let me try something more effective that can solve my problem.
Upvotes: 0
Views: 4236
Reputation: 305
As I was loading the manufacturer dropdown list on my childForm load event using the following function:
private void LoadManufacturers()
{
cmbManufacturer.Items.Clear();
DataTable dtManufacturers = DataAccess.Select("select manufacturername from tblmanufacturer order by manufacturername asc");
foreach (DataRow dr in dtManufacturers.Rows)
{
cmbManufacturer.Items.Add(dr[0].ToString());
}
//cmbManufacturer.SelectedIndex = 0;
}
While loading manufacturers on the page load event, I was also specifying the selected index of the dropdown list using the code cmbManufacturer.SelectedIndex = 0;
which I commented out later.
Once done, I then recalculate (re-query) the selected manufacturer (which the user want to update) within the load event of the dropdown list like this:
private void frmChildEditProduct_Load(object sender, EventArgs e)
{
LoadManufacturers(); // Calling the loadManufacturers function to load all the manufacturers to the dropdown list.
string manufacturerID = lblManufacturerId.Text;
DataTable dtMName = Products.SelectByManufacturerId(manufacturerID);
if (dtMName.Rows.Count > 0)
{
foreach (DataRow manufacturer in dtMName.Rows)
{
string manufacturerName = manufacturer[0].ToString();
cmbManufacturer.SelectedIndex = Convert.ToInt32(cmbManufacturer.FindStringExact(manufacturerName));
}
}
}
And my problem was solved. Thanks for the support I got on Stackoverflow.
Upvotes: 1
Reputation: 2499
To solve this and avoid future more complex codes it would be nice to read about DisplayMember
, ValueMember
properties.
To make this work with first two only simply do this:
public class Manufacturer
{
public int Id { get; set; } //Important to have get/set othervise DisplayMember and ValueMember properties will not work
public string Name { get; set; } //Important to have get/set othervise DisplayMember and ValueMember properties will not work
public static List<Manufacturer> GetAllManufacturers()
{
List<Manufacturer> list = new List<Manufacturer>();
//Read manufacturers one by one, create object of Manufacturer and then add that object to list
return list;
}
}
//This code below set in form constructor or on load
cmbManufacturer.DisplayMember = "Name";
cmbManufacturer.ValueMember = "Id;
cmbManufacturer.DataSource = Manufacturer.GetAllManufacturers();
//And now when you need to select manufacturer by id you do
cmbManufacturer.SelectedValue = 6; //Will select manufacturer which has id 6
//If you have updated your manufacturers in runtime and want to again load everything in combobox just do
cmbManufacturer.DataSource = Manufacturer.GetAllManufacturers();
Above is simple use of those two properties and down below i will show you more advanced one.
We will rewrite our Manufacturer
class like this:
public class Manufacturer
{
public int Id { get; set; }
public string Name { get; set; }
public string City { get; set; }
public string PersonInCharge { get; set; }
public string PhoneNumber { get; set; }
public static List<Tuple<string, Manufacturer>> GetAllManufacturers()
{
//This one i will make example with interaction to database
List<Tuple<string, Manufacturer>> list = new List<Tuple<string, Manufacturer>>();
using(SqlConnection con = new SqlConnection("SomeSqlString"))
{
con.Open();
using(SqlCommand cmd = new SqlCommand("Select Id, Name, City, Person, Phone from Manufacturers", con))
{
SqlDataReader dr = cmd.ExecuteReader();
while(dr.Read()) //Will read one by one line
{
Manufacturer m = new Manufacturer();
m.Id = Convert.ToInt32(dr[0]);
m.Name = dr[1].ToString();
m.City = dr[2].ToString();
m.PersonInCharge = dr[3].ToString();
m.PhoneNumber = dr[4].ToString();
list.Add(new Tuple<string, Manufacturer>(m.Id, m));
}
}
}
return list;
}
}
With class like this we have additional information about our manufacturer but how to display or store it? Well there our Tag comes in.
Tag is type of object which holds any additional object you want
So now we bind our DisplayMember
and ValueMember
like we have done above but now instead of directly binding datasource we will first save our list to separate variable:
List<Tuple<string, Manufacturers>> man = Manufacturer.GetAllManufacturers();
cmbManufacturer.DisplayMember = "item1"; //We use item1 and item2 since those are names of variables in Tuple<T>
cmbManufacturer.ValueMember = "item2"; //We use item1 and item2 since those are names of variables in Tuple<T>
cmbManufacturer.DataSource = man;
This way we have assigned item1
which is m.Name
which is name of our Manufacturer as DisplayMember
and assigned item2
which is Manufacturer
class which holds all other info about our manufacturer (Yea we can do it since ValueMember
is type of object
).
Now we have populated combobox but we will not be able to easily select item like this:
cmbManufacturer.SelectedValue = 6; //Will select manufacturer which has id 9
Since our SelectedValue
doesn't represent int
but Manufacturer
.
What we can do to solve this is create function inside form which will select it.
private void SelectManufacturerById(int id)
{
for(int i = 0; i < cmbManufacturer.Items.Count; i++)
{
Manufacturer m = (cmbManufacturer.Items[i] as Tuple<string, Manufacturer>).item2;
if(m.Id == id)
{
cmbManufacturer.SelectedItem = cmbManufacturer.Items[i];
return;
}
}
// Here throw some message since it couldn't find it
}
And maybe you still haven't got point why use tag property at all since it just makes this harder, well it is not since with selecting by id code, you can easily change it to select by some other value in Manufacturer
class, also you can add some more code to your Manufacturer class like
public void Update()
{
using(SqlConnection con = new SqlConnection("SomeSqlString"))
{
con.Open();
using(SqlCommand cmd = new SqlCommand("Update Manufacturers set Id = @id ....", con))
{
cmd.Parameters.AddWithValue("@id", m.Id);
//Assigning other paramterts
cmd.ExecuteNonQuery();
//Display message of success
}
}
}
and then inside your form with combobox you do something like this
Manufacturer m = cmbManufacturer.SelectedValue as Manufacturer; //We will get currently selected manufacturer inside combobox
m.Name = "Here we change name of it";
m.Update(); //Here we run function inside our class and it will update database and new name
And once again as i mentioned above, first code will solve your problem and make your life easier but if you get used to second one you will see more possibilities.
Upvotes: 1