sorting values in combobox by typing - c#

I have a combobox that is filled with data field JobCode from database. There are 1000s of jobcode and when the user needs to select one jobcode he has to scroll down through all the jobcodes in the combobox. Can I do it in such a way that if the user types some letter of jobcode it will show the jobcodes which start with that letter in the combobox at the top of list so the user can select easily. For example, like adding some code in keypressevent in combobox.
The user must still choose from jobcodes in the list, not keep partially or incorrectly entered data that will cause wrong data entry at insert and update time.
public void jobcomboboxload()
{
OleDbConnection oleDbConnection1 = new System.Data.OleDb.OleDbConnection(connString);
oleDbConnection1.Open();
OleDbCommand oleDbCommand1 = new System.Data.OleDb.OleDbCommand("Select jobpk,jobcode from jobcodemastertable", oleDbConnection1);
OleDbDataReader reader = oleDbCommand1.ExecuteReader();
DataTable dt = new DataTable();
dt.Columns.Add("jobpk", typeof(int));
dt.Columns.Add("jobcode", typeof(string));
dt.Load(reader);
cmbjobcode.ValueMember = "jobpk";
cmbjobcode.DisplayMember = "jobcode";
cmbjobcode.DataSource = dt.DefaultView;
oleDbConnection1.Close();
}
jobcode is an unique field.

Use cmbjobcode.AutoCompleteMode = AutoCompleteMode.Suggest (or other
values of the enum)
Use cmbjobcode.AutoCompleteSource = AutoCompleteSource.ListItems
Change your query including the clause ORDER BY on the field jobcode
Please, don't forget the using statement around your OleDbConnection, OleDbCommand and OleDbDataReader. This will assure the proper dispose of the before mentioned variables.
For the checking on incomplete values, you should add the Validating event and, in that event, check if the text entered is present in your strings.
The combobox has a method called FindStringExact() that can help.

Set your ComboBox AutoCompleteMode properties to Suggest AND AutoCompleteSource to ListItems or else you won't see the suggestion.
Like Steve said you can change your query and add ORDER BY on your request field to set the order in which you want them in your SELECT statement.
Hope this helps don't hesitate if you have any questions.

Related

DataTable update() inserts duplicate new rows without checking if it exists

I'm trying to use the update() method, but it is inserting my datatable data into my database without checking if the row exists, so it is inserting duplicate data. It is also not deleting rows that don't exist in datatable. How to resolve this? I want to synchronize my datatable with server table.
private void Form1_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the 'MyDatabaseDataSet11.Vendor_GUI_Test_Data' table. You can move, or remove it, as needed.
this.vendor_GUI_Test_DataTableAdapter.Fill(this.MyDatabaseDataSet11.Vendor_GUI_Test_Data);
// read target table on SQL Server and store in a tabledata var
this.ServerDataTable = this.MyDatabaseDataSet11.Vendor_GUI_Test_Data;
}
Insertion
private void convertGUIToTableFormat()
{
ServerDataTable.Rows.Clear();
// loop through GUIDataTable rows
for (int i = 0; i < GUIDataTable.Rows.Count; i++)
{
String guiKEY = (String)GUIDataTable.Rows[i][0] + "," + (String)GUIDataTable.Rows[i][8] + "," + (String)GUIDataTable.Rows[i][9];
//Console.WriteLine("guiKey: " + guiKEY);
// loop through every DOW value, make a new row for every true
for(int d = 1; d < 8; d++)
{
if ((bool)GUIDataTable.Rows[i][d] == true)
{
DataRow toInsert = ServerDataTable.NewRow();
toInsert[0] = GUIDataTable.Rows[i][0];
toInsert[1] = d + "";
toInsert[2] = GUIDataTable.Rows[i][8];
toInsert[3] = GUIDataTable.Rows[i][9];
ServerDataTable.Rows.InsertAt(toInsert, 0);
//printDataRow(toInsert);
//Console.WriteLine("---------------");
}
}
}
Trying to update
// I got this adapter from datagridview, casting my datatable to their format
CSharpFirstGUIWinForms.MyDatabaseDataSet1.Vendor_GUI_Test_DataDataTable DT = (CSharpFirstGUIWinForms.MyDatabaseDataSet1.Vendor_GUI_Test_DataDataTable)ServerDataTable;
DT.PrimaryKey = new DataColumn[] { DT.Columns["Vendor"], DT.Columns["DOW"], DT.Columns["LeadTime"], DT.Columns["DemandPeriod"] };
this.vendor_GUI_Test_DataTableAdapter.Update(DT);
Let's look at what happens in the code posted.
First this line:
this.ServerDataTable = this.MyDatabaseDataSet11.Vendor_GUI_Test_Data;
This is not a copy, but just an assignment between two variables. The assigned one (ServerDataTable) receives the 'reference' to the memory area where the data coming from the database has been stored. So these two variables 'point' to the same memory area. Whatever you do with one affects what the other sees.
Now look at this line:
ServerDataTable.Rows.Clear();
Uh! Why? You are clearing the memory area where the data loaded from the database were. Now the Datatable is empty and no records (DataRow) are present there.
Let's look at what happen inside the loop
DataRow toInsert = ServerDataTable.NewRow();
A new DataRow has been created, now every DataRow has a property called RowState and when you create a new row this property has the default value of DataRowState.Detached, but when you add the row inside the DataRow collection with
ServerDataTable.Rows.InsertAt(toInsert, 0);
then the DataRow.RowState property becomes DataRowState.Added.
At this point the missing information is how a TableAdapter behaves when you call Update. The adapter needs to build the appropriate INSERT/UPDATE/DELETE sql command to update the database. And what is the information used to choose the proper sql command? Indeed, it looks at the RowState property and it sees that all your rows are in the Added state. So it chooses the INSERT command for your table and barring any duplicate key violation you will end in your table with duplicate records.
What should you do to resolve the problem? Well the first thing is to remove the line that clears the memory from the data loaded, then, instead of calling always InsertAt you should first look if you have already the row in memory. You could do this using the DataTable.Select method. This method requires a string like it is a WHERE statement and you should use some value for the primarykey of your table
var rows = ServerDataTable.Select("PrimaryKeyFieldName = " + valueToSearchFor);
if you get a rows count bigger than zero then you can use the first row returned and update the existing values with your changes, if there is no row matching the condition then you can use the InsertAt like you are doing it now.
You're trying too hard, I think, and you're unfortunately getting nearly everything wrong
// read target table on SQL Server and store in a tabledata var
this.ServerDataTable = this.MyDatabaseDataSet11.Vendor_GUI_Test_Data;
No, this line of code doesn't do anything at all with the database, it just assigns an existing datatable to a property called ServerDataTable.
for (int i = 0; i < GUIDataTable.Rows.Count; i++)
It isn't clear if GUIDataTable is strongly or weakly typed, but if it's strong (I.e. it lives in your dataset, or is of a type that is a part of your dataset) you will do yourself massive favors if you do not access it's Rows collection at all. The way to access a strongly typed datatable is as if it were an array
myStronglyTypedTable[2] //yes, third row
myStronglyTypedTable.Rows[2] //no, do not do this- you end up with a base type DataRow that is massively harder to work with
Then we have..
DataRow toInsert = ServerDataTable.NewRow();
Again, don't do this.. you're working with strongly typed datatables. This makes your life easy:
var r = MyDatabaseDataSet11.Vendor_GUI_Test_Data.NewVendor_GUI_Test_DataRow();
Because now you can refer to everything by name and type, not numerical index and object:
r.Total = r.Quantity * r.Price; //yes
toInsert["Ttoal"] = (int)toInsert["Quantity"] * (double)toInsert["Price"]; //no. Messy, hard work, "stringly" typed, casting galore, no intellisense.. The typo was deliberate btw
You can also easily add data to a typed datatable like:
MyPersonDatatable.AddPersonRow("John, "smith", 29, "New York");
Next up..
// I got this adapter from datagridview, casting my datatable to their format
CSharpFirstGUIWinForms.MyDatabaseDataSet1.Vendor_GUI_Test_DataDataTable DT = (CSharpFirstGUIWinForms.MyDatabaseDataSet1.Vendor_GUI_Test_DataDataTable)ServerDataTable;
DT.PrimaryKey = new DataColumn[] { DT.Columns["Vendor"], DT.Columns["DOW"], DT.Columns["LeadTime"], DT.Columns["DemandPeriod"] };
this.vendor_GUI_Test_DataTableAdapter.Update(DT);
Need to straighten out the concepts and terminology in your mind here.. that is not an adapter, it didn't come from a datagridview, grid views never provide adapters, your datatable variable was always their format and if you typed it as DataTable ServerDataTable then that just makes it massively harder to work with, in the same way that saying object o = new Person() - now you have to cast o every time you want to do nearly anything Person specific with it. You could always declare all your variables in every program, as type object.. but you don't.. Hence don't do the equivalent by putting your strongly typed datatables inside DataTable typed variables because you're just hiding away the very things that make them useful and easy to work with
If you download rows from a database into a datatable, and you want to...
... delete them from the db, then call Delete on them in the datatable
... update them in the db, then set new values on the existing rows in the datatable
... insert more rows into the db alongside the existing rows, then add more rows to the datatable
Datatables track what you do to their rows. If you clear a datatable it doesn't mark every row as deleted, it just jettisons the rows. No db side rows will be affected. If you delete rows then they gain a rowstate of deleted and a delete query will fire when you call adapter.Update
Modify rows to cause an update to fire. Add new rows for insert
As Steve noted, you jettisoned all the rows, added new ones, added (probably uselessly) a primary key(the strongly typed table will likely have already had this key) which doesn't mean that the new rows are automatically associated to the old/doesn't cause them to be updated, hen inserted a load of new rows and wrote them to the db. This process was never going to update or delete anything
The way this is supposed to work is, you download rows, you see them in the grid, you add some, you change some, you delete some, you hit the save button. Behind the scenes the grid just poked some new rows into the datatable, marked some as deleted, changed others. It didn't go to the huge (and unfortunately incorrect) lengths your code went to. If you want your code to behave the same you follow the same idea:
var pta = new PersonTableAdapter();
var pdt = pta.GetData(); //query that returns all rows
pta.Fill(somedataset.Person); //or can do this
pdt = somedataset.Person; //alias of Person table
var p = pdt.FindByPersonId(123); //PersonId is the primary key in the datatable
p.Delete(); //mark person 123 as deleted
p = pdt.First(r => r.Name = "Joe"); //LINQ just works on strongly typed datatables, out of the box, no messing
p.Name = "John"; //modify joes name to John
pdt.AddPersonRow("Jane", 22);
pta.Update(pdt); //saves changes(delete 123, rename joe, add Jane) to db
What you need to appreciate is that all these commands are just finding or creating datarow obj3cts, that live inside a table.. the table tracks what you do and the adapter uses appropriate sql to send changes to the db.. if you wanted to mark all rows in a datatable as deleted you can visit each of them and call Delete() on it, then update the datatable to save the changes to the db

ComboBox SelectedItem Not Changing

Edit: I am using window forms
So, I want to change a value of NumericUpDown if the selected value in combo box changes.
I placed a data table items with the columns ID, itemName, itemPrice and Stock and set the DisplayMember property to itemName.
I used this code:
cmb.DisplayMember = "itemName";
cmb.DataSource = items;
Then to get the whole row of the selected item I used
DataRow dataRow = ((DataRowView)cmbItems.SelectedItem).Row;
The problem is that in the UI, the combo box's selected item does not changes no matter what I do but the value of the selected item changes.
Like this.
I first thought that my unit is just lagging but its not. How do I fix this?
You can try this code to check if the combobox will get the selected item when you make your option.
dbConn.Open();// this allows you to edit the database
string sql = "Select * from database1";
SqlCommand dbComm = new SqlCommand(sql, dbConn);
SqlDataAdapter dbAdapter = new SqlDataAdapter(dbComm);
DataTable dt = new DataTable();
dbAdapter.Fill(dt);
cmbDescription.DataSource = dt;
cmbDescription.DisplayMember = "itemName";
cmbDescription.ValueMember = "Enter the column name here";
cmbDescription.Text = "";
cmbDescription.Items.Add(dt);
cdbConn.Close(); //close connection to save all your inputs,calculations to the database
I found out that my code is very confusing and the system seem to be having problems while executing, I've rewritten the whole code for this window form and it is working now.

C# Filling Combo box with Column name of Database not Column values

I know it's been asked many times and there's so many resources about this but believe me i tried those, Unfortunately same thing is always happen. I really don't know why my combo box column value is repeating. Can someone help me in doing these in a proper way. Did i forgot something here ? Thank you
public void FillComboBox()
{
using (var con = SQLConnection.GetConnection())
{
using (var cmd = new SqlCommand("SELECT * FROM employee_product", con))
{
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
cbox_order.Items.Add("Code").ToString();
cbox_order.Items.Add("Model").ToString();
cbox_order.Items.Add("Itemdescription").ToString();
}
}
}
}
}
Here's the provided image
If you check the code, you are basically just adding the strings "Code", "Model" and "Itemdescription" to the combobox. I guess you want rather something like:
while (reader.Read())
{
cbox_order.Items.Add($"{reader["Code"]} {reader["Model"]} {reader["Itemdescription"]}");
}
In this snippet I am using the reader to get values of the columns in the returned row from the DB and then displaying joining those values in a single string that is then added to the ComboBox as an item.
Update
If you know the column names, why not just do this?
public void FillComboBox()
{
cbox_order.Items.Add("Code").ToString();
cbox_order.Items.Add("Model").ToString();
cbox_order.Items.Add("Itemdescription").ToString();
}
First load data into a DataTable:
var connection = #"Your connection string";
var command = "Your SELECT command text";
var table = new DataTable();
using (var adapter = new SqlDataAdapter(command, connection))
adapter.Fill(table);
To show list of columns in a ComboBox:
comboBox1.DataSource = table.Columns.Cast<DataColumn>().ToList();
comboBox1.ValueMember = "ColumnName";
comboBox1.DisplayMember = "ColumnName";
To show data in DataGridView:
dataGridView1.DataSource = table;
In above code I suppose you are going to show columns of the table which you also want to load its data at the same time. In case which you just want to load just column information, you can use:
adapter.FillSchema(table, SchemaType.Mapped);
actually your not using your DataReader but you just add Code, Model and ItemDescription item for each row found with the MySQL query.
cbox_order.Items.Add("Code").ToString();
cbox_order.Items.Add("Model").ToString();
cbox_order.Items.Add("Itemdescription").ToString();
If you want to use the result of the MySQL query you can try this instead:
cbox_order.Items.Add(reader["Code"].ToString()).ToString(); // Change "Code" by the column name into the database
cbox_order.Items.Add(reader["Model"].ToString()).ToString(); // Change "Model" by the column name into the database
cbox_order.Items.Add(reader["Itemdescription"].ToString()).ToString(); // Change "Itemdescription" by the column name into the database
Don't forget to close the reader at the end
reader.Close();
EDIT
if you want the column name instead of data you can use this query, but that's useless if you already know the column name.
SELECT COLUMN_NAME FROM information_schema.columns WHERE table_schema='databasename' AND table_name='tablename'
Try to close and dispose of reader and close the connection.
reader.close;
reader.dispose;
con.close();

Populate textbox after scanning barcode

Is it possible to fetch data from database after scanning the barcode? example my student ID is 201312345, after scanning my ID is it possible to populate the textboxes with my infos like name, address, course, et.? Thanks
yes thats possible!
Put the scanned student ID in a variable, make a query where you select the things you want from your database
EXAMPLE:
SqlCommand sqlSelectStudentData = new SqlCommand(SELECT * FROM tablename WHERE studentid=#studentid);
sqlSelectStudentData.Parameters.AddWithValue("#studentid", 'your scanned student id');
Put the values that return from the query in some labels or in what objects you want.
Good Luck!
string ValueOfScanner;
SqlCommand sqlcmGetStudentInfo = new SqlCommand("SELECT * FROM tablename WHERE studentid=#studentid ", connectionstring);
GetStudentInfo.Paramaters.AddWithValue("#studentid", ValueOfScanner);
SqlDataReader msGetInfo = GetStudentInfo.ExecuteReader();
DataTable dtGetInfo= new DataTable();
dtGetInfo.Load(msGetInfo);
foreach(DataRow row in dtGetInfo.Rows)
{
labelStudentName = row["studentinfo"].ToString();
labelStudentAdress = row["studentadress"].ToString();
labelStudentCourse = row["studentcourse"].ToString();
labelStudentSchool = row["studentschool"].ToString();
//And so on!
}
This is the code that should do the job. Make the query fit to your database and the tablename values to your tablenames. And put the value of what the scanner scans in the string ValueOfScanner!
Hope this helps you further
What you need to do is execute your SQL query in a TextBox TextChanged Event.
So when you scan your userId and the textbox is populated with the value, it will call a textChanged Event. This method will execute the query and get the information for the studentId from the Database that you can fill your form or whatever you have.
This is how I will do it.
Nothing special with it, the barcode scanner acts just like a keyboard and at the end of the reading it will emit an enter key so the only thing that you have to do is handle that event or whatever your logic is.

duplicity in combo-box when i fill

i have this code for fill combo-box
SQL = "SELECT DISTINCT Name,Num FROM MyTbl order by Name";
adp = new OracleDataAdapter(SQL, Conn);
adp.Fill(dsNa, "MyTbl");
adp.Dispose();
comFna.DataSource = dsNa.Tables[0];
comFna.DisplayMember = dsNa.Tables[0].Columns[0].ColumnName;
comFna.ValueMember = dsNa.Tables[0].Columns[1].ColumnName;
but after inserting new Name - i dont see hem
and after i run this code again - i see duplicity records (only in the combobox)
how to solve this ? (i work on C# Winforms)
thank's in advance
when you add new name to database you have two choices:
1) create a new item with given name (and num value) and insert it into combobox items collection.
2) re-load combobox from database (which you are using)
the only problem is that you need to clear combobox items or set its datasource to null before re-binding it.
adp.Dispose();
comFna.DataSource = null; //ADD THIS LINE HERE OR comFna.Items.Clear();
comFna.DataSource = dsNa.Tables[0];
comFna.DisplayMember = dsNa.Tables[0].Columns[0].ColumnName;
comFna.ValueMember = dsNa.Tables[0].Columns[1].ColumnName;
comFna.Items.Clear();
before filling your comboBox, use this code to remove old items, and then re-fill it.

Categories

Resources