Same two items in combobox but first one always gets selected C# - c#

I've got really weird problem with combobox on my windows form application.
So my combobox is populated using datasource, it displays names of people and it holds their IDs as cmbRequestor.ValueMember.
public BindingSource requestorBindingSource = null;
private const string cmdAssoc = "SELECT * FROM assoc_vw ORDER BY assoc_name";
requestorBindingSource.DataSource = populateDataTable(cmdAssoc);
cmbRequestor.DisplayMember = "assoc_name";
cmbRequestor.ValueMember = "ID";
cmbRequestor.DataSource = requestorBindingSource;
cmbRequestor.SelectedIndex = 0;
It works fine but if there is an instance of people with the same name and I select 2nd name (of the same name) from the combobox, for some reason once I close the combobox it selects the first name even though I selected 2nd name.
So to make sure they hold different values against their names I have created SelectedIndexChanged event.
private void cmbRequestor_SelectedIndexChanged(object sender, EventArgs e)
{
int x = cmbRequestor.SelectedIndex;
string j = cmbRequestor.SelectedValue.ToString();
var y = cmbRequestor.Items[x];
}
When I debug the code and I select 2nd name (of the same name) the ID behind it is 3069. Once I close the combobox and click save to save the form SelectedIndexChanged is triggered again (that should not happen) and it goes to the first person with the same name and its ID is different.
There are no other events on this control and I dont use it anywhere else. It looks like the control gets confused itself if there is an instance of the same name.

Change DropDownStyle property to DropDownList. Default value is DropDown and in that case selected item will be determined by the first matched text in the list. DropDown is mainly used in conjunction with autocomplete logics.
EDIT:
If you have to stick with DropDown style, the best workaround will be to handle DropDownClosed event, at that point you will have the correct index selected.

I found that if I set FormattingEnabled to false in Properties, that it works.

I had also the same problem... The best solution for me was to change the DropDown Style property of the combo Box to DropDownList.
When I needed the DropDown style (e.g. to input new data in the Combo Box) I was changing the property to DropDown in the code... and changing back to DropDownList when finished.

try using ComboBox.SelectionChangeCommitted Event for the combobox and maybe you need to remove the default selected index which is set to zero

conn1 = JdbcConn.getConn();
try
{
conn1.Open();
String sqllogin = "Select *from tbladdpattern ";
var cmd = new MySqlCommand(sqllogin, conn1);//This is sql query execute
var reader = cmd.ExecuteReader();//Execute query
IList<string> listName = new List<string>();
while (reader.Read())
{
listName.Add(reader[1].ToString());
}
// listName = listName.Distinct().ToList();
comboBox1.DataSource = listName.Distinct().ToList();
conn1.Close();//Close DataBase Connection
}
catch (Exception ex)
{
conn1.Close();
LogCreate.WriteLog("Errorn in show all pattern " + ex);
}

Related

Check duplicates before copying rows from one datagrid to another datagrid

Actually I am copying rows from one datagrid to another on DataGridView Double Click Event, and it's going well. The code is here:
//Void App
void AddProducts(int ProdID, string Name, string ProductCode, int RetailPrice, int SalePrice, string BrandName, string Category, int QTY)
{
string[] row = { Convert.ToUInt32(ProdID).ToString(), Name, ProductCode,
Convert.ToInt32(RetailPrice).ToString(), Convert.ToInt32(SalePrice).ToString(), BrandName, Category, Convert.ToInt32(QTY).ToString()};
dgViewProductsToSell.Rows.Add(row);
}
//Code
private void dgViewProducts_MouseDoubleClick(object sender, MouseEventArgs e)
{
string Name1 = this.dgViewProducts.CurrentRow.Cells["Name"].Value.ToString();
int ProdID = Convert.ToInt32(dgViewProducts.CurrentRow.Cells["ProdID"].Value);
string Name = dgViewProducts.CurrentRow.Cells["Name"].Value.ToString();
string ProductCode = dgViewProducts.CurrentRow.Cells["ProductCode"].Value.ToString();
int RetailPrice = Convert.ToInt32(dgViewProducts.CurrentRow.Cells["RetailPrice"].Value);
int SalePrice = Convert.ToInt32(dgViewProducts.CurrentRow.Cells["SalePrice"].Value);
string BrandName = dgViewProducts.CurrentRow.Cells["BrandName"].Value.ToString();
string Category = dgViewProducts.CurrentRow.Cells["Category"].Value.ToString();
int QTY = Convert.ToInt32(dgViewProducts.CurrentRow.Cells["QTY"].Value);
AddProducts(Convert.ToInt32(ProdID), Name, ProductCode, Convert.ToInt32(RetailPrice), Convert.ToInt32(SalePrice), BrandName, Category, Convert.ToInt32(QTY));
}
How I can check duplicate entries before copying the rows? So the 2nd datagridview could avoid duplicate entries.
I'm going to start off with this scrappy test app:
Don't worry that it's a screenshot of code - that's just for information purposes of how it came to be that I generated a datagridview with some data in it. This is how do "do it properly" - you keep your data in a DataTable and you use a grid to show it
The next step: we are going to make a strongly typed dataset, datatable, set its primary key, put it on the form along with a datagridview it is bound to, and we are going to fill it uniquely by double clicking the existing grid. I modeled the existing grid more like you have done. In reality I would make BOTH these grids be based on a strongly typed data table, but I wanted to show you you didn't have to, and my advice for making a strongly typed datatable can fit in with your existing idea of stuffing data into a datagridview directly, until you're ready to change over
Add a new DataSet type item to your project. Right click the project, Add.. New Item:
Give it a nice name. Nothing worse than code full of Form1, DataSet1, GridView3, Button27
When it's added, double click it to open the design surface. Right click the surface and add a new datatable:
Give it a nice name, right click it repeatedly and add columns for all you want, Name, Code, Price etc:
Don't forget to give them a datatype too, so not everything is a string!
You said you want to be unique by name so.. Click in the grey bit next to Name so the row goes all blue, then right click and choose Set primary key
Save it all, close the dataset designer, go to the forms designer, click the VIEW menu, go to OTHER WINDOWS >> DATASOURCES. You can also press Shift+Alt+D
Open the DATA SOURCES panel, find the grid node of your datatable (whatever you called it) and drag it onto the form
A datagridview, connected to your custom datatable has appeared, together with some new things at the bottom. You can delete the bindingnavigator:
(and rename the dataset instance so it has a nicer name than xxxxDataSet1)
That's all the setup we need for now to set up the receiver datatable, and grid. Let's edit the event handler for the mouse double click. I jiggled things around a bit and added another feature as a demonstration, that if the row IS there we can update it, otherwise we add it:
private void _dataGridViewSrc_MouseDoubleClick(object sender, MouseEventArgs e)
{
//my source datagrid is bound to a datatable. I use this to retrieve the current row related
//to the row in the grid that was double clicked
DataRow sourceRow = (_dataGridViewSrc.CurrentRow.DataBoundItem as DataRowView)?.Row;
if(sourceRow == null)
return;
//because we made Name the primary key, the strongly typed datatable has a FindByName method
//we pass it the string Name from the source datatable row (a grid row cell value in your case)
NiceNameDataSet.UniqueProductsRow destRow = _niceNameDataSet.UniqueProducts.FindByName((string)sourceRow["Name"]);
//FindByName returns NULL if the row wasn't found
if(destRow == null)
{
//the row isn't there, so add it, using the data from the source row
_niceNameDataSet.UniqueProducts.AddUniqueProductsRow(
(string)sourceRow["Name"],
(string)sourceRow["Code"],
(double)sourceRow["Price"]
);
} else
{
//the row IS there, how about we update the fields using the row that was just clicked?
//this demonstrated how much nicer it is to work with a strongly typed dataset/datatable
//because all the columns have proper Properties, like row.Code, with proeprt datatypes
//like string and double, rather than having to be referred to with a string name like
//row["Code"] and having to be cast from object to string, double all the time: messy
//and error prone
destRow.Code = (string)sourceRow["Code"];
destRow.Price = (double)sourceRow["Price"];
}
}
I changed the prices and codes a bit to demo this other featuer. Now you can double click either bread row as much as you like and you only get one row in the destination grid, and it changes its values back and forth:
You can create an object which represents each row with properties for each column. For this object you can create an public bool Equals(object obj) method.
With the object you can compare already read objects with newly read objects. Either manually or by using something Contains or similar methods which are part of List<> and Dictionary<> classes.
It all depends on how much data you have and which line you consider to be equal to another line. Is it equal / a collision if the product ID is a duplicate or do all properties also have to match
Each row should have a primary key, usually an ID. I am assuming this is the case for you.
Second assumption: both datagridview controls are bound to datatables/datasets or binding sources.
So, when the user selects a row in the grid, retrieve the underlying datarow. This can be done using the databounditem function. Then you can fetch the ID or primary key.
Then compare the two datatables. This is more efficient and safer than accessing UI controls. There are different ways to check that a record already exists in a datatable, for example the select function. Another option is using LINQ.
Do not try to update the second datagridview directly, instead you add a record to its underlying datatable, and you let the datagridview update itself.
Your code seems to be unsafe. What happens if the user double-clicks on the edges of the grid ? The current row could be -1. You need to add a check.
You should also test what happens if the user sorts the columns in the datagrid or drag the columns to change the display order.
To sum up I strongly advise to use datatables, even if you are not reading from or saving to database.
You can use the following code to remove duplicate entries before copying the datagridview.
Code:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
DataTable table = new DataTable();
table.Columns.Add("Name");
table.Columns.Add("Id");
table.Columns.Add("Age");
table.Rows.Add("test1",1001,22);
table.Rows.Add("test1", 1001, 22);
table.Rows.Add("test2", 1002, 23);
table.Rows.Add("test3", 1003, 24);
dataGridView1.DataSource = table;
}
private void dataGridView1_MouseDoubleClick(object sender, MouseEventArgs e)
{
DataTable dt = (DataTable)dataGridView1.DataSource;
dt = dt.DefaultView.ToTable(true);
dataGridView2.DataSource = dt;
}
}
Result:
I don't know if I correctly understand your question but maybe this will help
before adding into my gridview I already checked the possibility of duplicate
//Validate duplicate data b4 adding to gridview
for (int i = 0; i < dataGridView2.Rows.Count; i++)
{
if (textBox1.Text == dataGridView2.Rows[i].Cells[1].Value.ToString())
{
MessageBox.Show("Product already on the list, if you wish to add this product click the product name and edit the quantity", "System Message", MessageBoxButtons.OK, MessageBoxIcon.Information);
textBox1.Text = "";
textBox2.Text = "";
textBox1.Focus();
return;
} else { }
}
then pass the datagridview1(form1) to datagridview2(form2)
List<PurChaseRcpT> cdgv = new List<PurChaseRcpT>();
foreach (DataGridViewRow Item in dataGridView2.Rows)
{
cdgv.Add(new PurChaseRcpT {
Particular = Item.Cells[0].Value.ToString(),
Qty = Item.Cells[2].Value.ToString(),
UM = Item.Cells[3].Value.ToString(),
Price = Item.Cells[4].Value.ToString(),
Total = Item.Cells[5].Value.ToString()
});
}
FrM_SubChange ChangeFrm = new FrM_SubChange();
ChangeFrm.dataGridViewPassed = this.dataGridView2;
ChangeFrm.TempVal = cdgv;
ChangeFrm.Show();
hope it help..

ComboBox Index Changed

Need to know: I am working with Windows Forms in Visual Studio and C#.
I have 5 comobobox's that I populate from SQL with the parts available in the DB. Part of the coding to it, one uses a DataTable and set the DataSource of the comboBox to that DataTable.
In this same DataTable via my SQL query, I have listed the cost of the part in the list. What I want to do is whichever part you pick from the dropdown list, the related price must show in the textbox next to it.
I am trying to use the comboBox1_SelectedIndexChanged for this, but the problem I run into is as soon as the DataSource gets set to the DataTable while the form's initial loading, it gets picked up as a Index change and the comboBox1_SelectedIndexChanged wants to run. But at this point in time, the SelectedIndex Value is null due to it still loading, causing it to give me a exception cast error.
how can I work around this?
DataTable SparePart = new DataTable() is declared outside the function to make it available as "public" so that the comboBox1_SelectedIndexChanged can access it.
Then I have this code to populate the comboBox:
//Read Status info from DB
SqlDataAdapter SparePartReader = new SqlDataAdapter(SQLSparePartDropbox);
SparePartReader.Fill(SparePart);
comboBoxFinJCSpares1.DataSource = SparePart;
comboBoxFinJCSpares1.DisplayMember = "DisplayMember";
comboBoxFinJCSpares1.ValueMember = "PartID";
//Set Combox1 affiliated Cost value to cost textbox
int ComBo1PartID = (int)comboBoxFinJCSpares1.SelectedValue;
string CostPrice = (from DataRow dr in SparePart.Rows
where (int)dr["PartID"] == ComBo1PartID
select (string)dr["PartCost"]).FirstOrDefault();
textBoxFinJCCost1.Text = CostPrice.ToString();
and then I have this for the comboBoxFinJCSpares1_SelectedIndexChanged:
//Set Combox1 affiliated Cost value to cost textbox
int ComBo1PartID = (int)comboBoxFinJCSpares1.SelectedValue;
string CostPrice = (from DataRow dr in SparePart.Rows
where (int)dr["PartID"] == ComBo1PartID
select (string)dr["PartCost"]).FirstOrDefault();
textBoxFinJCCost1.Text = CostPrice.ToString();
enter image description here
The solution is as easy as making one boolean variable and call it formLoaded.
Set it to false, then set it to true after the form loads.
Put your code for populating combobox inside if statement and that should do it
Cheers ~ ChenChi
demo:
//Read Status info from DB
if(formLoaded)
{
SqlDataAdapter SparePartReader = new SqlDataAdapter(SQLSparePartDropbox);
SparePartReader.Fill(SparePart);
comboBoxFinJCSpares1.DataSource = SparePart;
comboBoxFinJCSpares1.DisplayMember = "DisplayMember";
comboBoxFinJCSpares1.ValueMember = "PartID";
//Set Combox1 affiliated Cost value to cost textbox
int ComBo1PartID = (int)comboBoxFinJCSpares1.SelectedValue;
string CostPrice = (from DataRow dr in SparePart.Rows
where (int)dr["PartID"] == ComBo1PartID
select (string)dr["PartCost"]).FirstOrDefault();
textBoxFinJCCost1.Text = CostPrice.ToString();
}
Thanks guys, the "SelectedChangeCommitted" option suggested by Marcel Hoekstra solved my problem.

Number of comboboxes increase after the first set of results

I am populating my datagrid based on a value in the textbox.
One of the field values in my grid view is a combobox.On a particular text box entry it shows me the correct results but wen I give another value in the text box, the combobox increases its number which means If I enter 100, the data is populated correctly in my combobox but for any value that is provided next the number of combobox becomes 2.I don't know why this happens. This is the code on button click. please help
DataGridViewComboBoxColumn combo = new DataGridViewComboBoxColumn();
combo.HeaderText = "Supplier";
//execute sql data adapter to get supplier values
DataTable dt = obj.SqlDataTable("select name1 from blahblah");
//foreach (DataRow supplier in dt.DataSet.Tables[0].Rows)
//{
// combo.Items.Add(supplier[0]);
//}
//dataGridView1.Columns.Add(combo);
foreach (DataRow row in dt.Rows)
{
combo.Items.Add(row["NAME1"].ToString());
}
dataGridView1.Columns.Add(combo);
You're adding a new combobox on every click... instead check if the comboboxColumn is already added and appropriately modify its contents if it is already present.
To do this check, name your combobox column like this:
combo.Name = "Supplier";
the name property will not show in the UI, but Windows Forms will remember it. Then, you can test if your column is already added with:
if (!dataGridView1.Columns.Contains("Supplier"))
I'm not sure about the textbox, but everytime you click, a new DataGridViewComboBoxColumn is added to the grid. If you click 5 times, you'll see 5 DataGridViewComboBoxColumns with the dropdown being the result of the sql query.
You would need to check if the DataGridViewComboBoxColumns combo was already added:
if (dataGridView1.Columns.IndexOf(combo) < 0)
{
// Add
}

Combobox textChanged event not firing

We have customar table contains Cust_ID, Cust_Name etc.....
for this table Cust_Name is not unique and one Customer name can repeat Number of times.
i am getting data from SQL and binding to ComboBox (winform)
cmbCustomar.Datasource = GetCustomerData(_LocationID);
cmbCustomar.DisplayMember = "Cust_Name";
cmbCustomar.ValueMember = "Cust_ID";
Here the Problem is :
Customer Name : JOHN is repeated 4 times, all Cust_ID are different
when user select JOHN on first Item i am getting correct "SelectedValue"
but if user select 2 nd or 3rd JOHN
Combobox Item it allways default select First Item (Name as JOHN)
and the SelectedValue allways return the First Item Value.
i am not able to find where i am doing wrong, please suggest.
Try changing the following property:
cmbCustomar.DropDownStyle = DropDownList;
If your ComboBox has DropDownStyle = DropDown, then the "text" part of the ComboBox is trying to match the first item it can find in the list, and in this case, it ignores the current selected item and finds the first "John" on your list.
Keep in mind "SelectedValueChanged" event will fire when combobox being populated. Make sure to un-subscribe to this event before populating the combobox. and subscribe again after populating the data.
//unsubsribe the event before populating combobox1
this.cmbCustomar.SelectedValueChanged -= new System.EventHandler(this.cmbCustomar_SelectedValueChanged);
cmbCustomar.Datasource = GetCustomerData(_LocationID);
cmbCustomar.DisplayMember = "Cust_Name";
cmbCustomar.ValueMember = "Cust_ID";
//subscribe the event again
this.cmbCustomar.SelectedValueChanged += new System.EventHandler(this.cmbCustomar_SelectedValueChanged);
It seems that you are very new to it. And as by my guess, because of your incomplete description, you are trying return the "Selected Value" based on the selected text of the combobox. But rather than that you must try to attach a value a to selected text and return that value. It will surely solve your problem.
Hope it helps.

TextBox AutoComplete from MDB

I have a .Net 4 Windows Forms app that uses a Microsoft Access Database with one table which has three columns CityCode, Name and Country.
What I want to do is have an autocomplete which shows the “Name” and “Country” but when selected the “CityCode” Value is shown in the textbox. In addition if the user types A City Code eg LAX as they type L it would list all the cities whose code or Name starts with L.
Can this be done?
Currently I have the following for access the database (but it seems to be a bit slow!)
textBoxCity.AutoCompleteCustomSource = CityList();
public static AutoCompleteStringCollection CityList()
{
string connectionStringLD = string.Empty;
connectionStringLD = #"Driver={Microsoft Access Driver (*.mdb)};DBQ=c:\CityList.mdb";
string SQL = "SELECT CityCode from CityTable";
OdbcConnection conn = new OdbcConnection(connectionStringLD);
OdbcCommand cmd = new OdbcCommand(SQL);
cmd.Connection = conn;
conn.Open();
OdbcDataReader reader = cmd.ExecuteReader();
AutoCompleteStringCollection theCityList = new AutoCompleteStringCollection();
while (reader.Read())
{
theCityList.Add(reader.GetValue(0).ToString());
}
return theCityList;
}
You can use Like '%' Query in your Sql Statement which will return the city name based on your input.
You can Refer this example Sql Parameter with C# Using Like wildCards
I'm not sure what you're getting at with
What I want to do is have an autocomplete which shows the “Name” and “Country” but when selected the “CityCode” Value is shown in the textbox.
but I can answer the autocomplete part of your question.
To do this you need to get your data into a DataTable; you can read it from the database into the table however you want, but the Right Way to do it is to use OleDbConnection, OleDbDataAdapter, and OleDbCommandBuilder - msdn has examples.
Now that it's in a DataTable, bind it to a ComboBox:
var query =
from row in mytable.AsEnumerable()
select new { citycode = row.Field<string>("CityCode") } // put whatever you want in the anonymous type
mycombobox.DisplayMember = "citycode"
mycombobox.ValueMember = "citycode" // this one can be a different member name
mycombobox.DataSource = query.toList(); // the datasource should be set last
And now you can set the combo box behavior to be an autocomplete:
combobox1.AutoCompleteMode can be set to Append (to simply autocomplete), Suggest (to bring up a dropdown box), or SuggestAppend (both)
Set combobox1.AutoCompleteSource to ListItems to have it get the autocomplete entries from the data binding.
If you prefer to allow users to type whatever they want and only suggest your datatable values as options, then you should only set the AutoCompleteCustomSource and not worry about actual data binding with DataSource.
This is kind of all a lot of trouble; since cities aren't exactly going to be opening international airports several times a second you might prefer just dumping all the airport codes into a List, which you can also data bind to.

Categories