Efficient way to retrieve multiple values from the same column - c#

I want to set some buttons text (content) with values I retrieve from a mysql.
till now I always did it like this:
if (rdr.Read())
{
Item1.Visibility = Visibility.Visible;
Item1txt.Text = rdr.GetString("item_name");
}
if (rdr.Read())
{
Item2.Visibility = Visibility.Visible;
Item2txt.Text = rdr.GetString("item_name");
}
if (rdr.Read())
{
Item3.Visibility = Visibility.Visible;
Item3txt.Text = rdr.GetString("item_name");
}
This way works fine because I retrieve the right values in each button, but it makes the readability horrible..
When I started this project I had zero knowledge of C# so I tried some things like:
while (rdr.Read())
{
Item4.Visibility = Visibility.Visible;
Item4txt.Text = rdr.GetString("item_name");
Item5.Visibility = Visibility.Visible;
Item5txt.Text = rdr.GetString("item_name");
}
But this gave me the same value retrieved from my database in my buttons..
example:
button 1: test1 | button 2: test1 | button 3: test1.. etc..
what i need:
button 1: test1 | button2: test2 | button 3: test3.. etc..
Now my knowledge of C# is getting better every day so I want to learn some new things.
Right now I'm trying to use the foreach loop but I have a feeling I'm missing something:
using (MySqlConnection conn = new MySqlConnection(_CS))
{
conn.Open();
string cmd = "SELECT * FROM ordertopos LIMIT 10";
MySqlCommand custid = new MySqlCommand(cmd, conn);
using (MySqlDataReader rdr = custid.ExecuteReader())
{
System.Data.DataTable dt = new System.Data.DataTable();
dt.Load(rdr);
foreach (System.Data.DataRow row in dt.Rows)
{
Orderl1.Text = row["customerid"].ToString();
}
}
}
Essentially I want to know how I can set the content of my buttons, retrieved from mysql, in a more efficient en easier to maintain code..
I'm fairly new with foreach, so please be specific.

i would recommend to do it in several step's for a better reusability
Step 1
List<string> myItems;
using (MySqlConnection conn = new MySqlConnection(_CS))
{
conn.Open();
string cmd = "SELECT * FROM ordertopos LIMIT 10";
MySqlCommand custid = new MySqlCommand(cmd, conn);
using (MySqlDataReader rdr = custid.ExecuteReader())
{
myItems= new List<string>();
while (rdr.Read())
{
myItems.Add(rdr.GetString("item_name"));
}
}
}
Step 2
modified Olivier Jacot-Descombe version
for(int i =0; i< myItems.count; i++) {
Button btn = FindChild<Button>(this, "Item" + i); //"this" will be the control which contains your button's
TextBlock tb = FindChild<TextBlock>(btn, "Item" + i + "txt");
btn.Visibility = Visibility.Visible;
tb.Text =myItems[i];
i++;
}

If you want to scale your problem in order to use loops than you need to have a List or an Array that contains objects for which you want to set values of properties. In your particular case, put your Orders in a List<Order> and then you could use something like this:
int count = 0;
foreach (System.Data.DataRow row in dt.Rows)
{
if(count<orders.Count)
orders[count++].Text = row["customerid"].ToString();
}

You need to traverse through your Items to set respective values. As DJ Kraze suggested, you are just overwriting the same control. And it will have the last accessed value (as it won't be overwritten once loop has ended).
You you just need to have somehow reference to your target controls, or if you are creating controls on the fly, than you can simply pass reference of newly created control every time you access a row from database.

You can access controls by their name instead of their member variable by using the FindChild method found here: WPF ways to find controls.
int i = 1;
while (rdr.Read()) {
Button btn = FindChild<Button>(this, "Item" + i);
TextBlock tb = FindChild<TextBlock>(btn, "Item" + i + "txt");
btn.Visibility = Visibility.Visible;
tb.Text = rdr.GetString("item_name");
i++;
}
This enables you to loop through them by using a counter (i).

Related

how to make the datagridview load faster with Multiple Row query - c# SQL

The code:
private void suppPopulate()
{
byCode.Text = "Supplier Code";
byDesc.Text = "Supplier";
DGViewListItems.Columns.Add("custcode", "Customer Code");
DGViewListItems.Columns.Add("customer", "Customer");
DGViewListItems.Columns[0].ReadOnly = true;
DGViewListItems.Columns[0].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
DGViewListItems.Columns[1].ReadOnly = true;
DGViewListItems.Columns[1].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
using (SqlConnection con = db.Connect())
{
SqlDataReader rd;
SqlCommand cmd = new SqlCommand("SELECT DISTINCT custcode, custname FROM Customers WHERE type = 'V';", db.Connect());
rd = cmd.ExecuteReader();
int i = 0;
if (rd.HasRows)
{
while (rd.Read())
{
DGViewListItems.Rows.Add();
DGViewListItems.Rows[i].Cells["custcode"].Value = rd["custcode"].ToString().Trim();
DGViewListItems.Rows[i].Cells["customer"].Value = rd["custname"].ToString().Trim();
}
}
cmd.Connection.Close();
}
}
The SSMS output:
The output form loads slowly, the rows for the query are over 1000 so I think the cause of the slow load is the number of returned rows? If yes, how do make the load of the datagridview faster?
NOTE - this answer relates to the first part of the original question regarding why only a single row of the DataGrid being populated.
Incrementing the counter "i" at the bottom of the while loop looks like it may fix the problem.
You are adding rows, but only updating the first.

How to retrieve data from database to CheckedListBox and set the items as checked?

I am new in WPF. I am trying to load the values from database to fill in CheckedListBox. Based on a condition, some items must be set to checked while loading in checkedlistbox.
How to do this? I have tried the code below, items are loaded in CheckedListBox, but are not checked.
Below is values loaded to checked listbox
public void fillcheck()
{
con = new SqlConnection(connectionstring);
con.Open();
string comboquery = "SELECT [Machine] FROM Department Where active='True'";
SqlCommand cmd = new SqlCommand(comboquery, con);
SqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
string fil1 = rdr.GetString(0);
Checkedlistbox1.Items.Add(fil1);
}
rdr.Close();
}
int departmentID=60//for just refer
Object[] jobs = CheckedlistBox1.Items.Cast<Object>().ToArray();
foreach (Object obj in jobs)
{
string query = "SELECT [Machine] FROM Department Where ID='" + departmentID+ "'";
SqlCommand cmd = new SqlCommand(query, con);
SqlDataReader rdr = cmd.ExecuteReader();
while(rdr.Read())
{
string mac = rdr.GetString(0);//Here i get two values(XRAY,CT)but finally shown CT only be checked,so how to do both checked
if (mac == obj.ToString())
{
int indexx = CheckedlistBox1.Items.IndexOf(mac);
if (indexx >= 0)
{
CheckedlistBox1.SetItemChecked(indexx, true);
}
}
}
rdr.Close();
}
You need to transfer your SqlDataReader rdr content to a DataTable. That will help you get a DataTable object containing multiple rows like you have mentioned.
Now for the next step, you can apply a foreach on that DataTable object to iterate over all its rows like this :
foreach(DataRow dr in dt.Rows)
{
if(yourCondition)
{
//set isChecked = true for the checkbox.
}
}
UPDATE :
Try modifying your while loop like this :
while (rdr.Read())
{
string mac = rdr.GetString(0);
ListItem li = new ListItem();
li.Value = "yourBindedValue";// some value from database column
li.Text = "yourBindedText";// use mac if its text.
int index = Checkedlistbox1.Items.IndexOf(li);
if (index >= 0)
{
Checkedlistbox1.SetItemChecked(index, true);
}
}
I have tested this and it works. You just have to pass the Text and Value of the CheckBoxListItem that you are trying to find in the li object and you can get the index if it exists. Make sure you pass both the attributes.
You should have used code-
foreach (int indexChecked in chlstBox.Items)
instead of
foreach (int indexChecked in chlstBox.CheckedIndices)
At start you have 0 selected items and thats why your outer for loop is not working..
EDIT-
Basic Logic is also incorrect.
You should loop through dataset, find the string in checkboxlist and then check it. So, outer foreach loop is not required. Also, make sure that you are using correct checkboxlist variable. In for loop you are using chlstBox
and while searching you are using Checkedlistbox1 ....

Can't figure out why my results are appearing with ListBox{"name"}

public void loadAllEmployeesFromSQLServer()
{
SqlConnection conn = new SqlConnection();
SqlCommand cmd = new SqlCommand();
conn.ConnectionString = "Server=WIN2008SERVER;Database=Kiosk;Uid=kiosk;Pwd=kiosk;";
conn.Open();
string query = "SELECT [displayName],[activeDirectoryName],[roleID],[activeAccount] FROM [ProbationKiosk].[dbo].[Employees]";
cmd.Connection = conn;
cmd.CommandText = query;
SqlDataReader dr = cmd.ExecuteReader();
ArrayList allEmployees = new ArrayList();
while (dr.Read())
{
employees emp = new employees(dr["displayName"].ToString(), dr["activeDirectoryName"].ToString(), dr["roleID"].ToString(), Int32.Parse(dr["activeAccount"].ToString()));
allEmployees.Add(emp);
string[] employeeData = new string[3];
employeeData[0] = emp.commonName;
employeeData[1] = emp.activeDirectory;
employeeData[2] = emp.currentRole;
ListViewItem lvi = new ListViewItem(employeeData);
if (emp.isActive == 1)
{
checkedListBox1.Items.Add(lvi, true);
}
else
{
checkedListBox1.Items.Add(lvi, false);
}
}
}
I made my CheckedListBox a multicolumn table.
I debugged my code and I am getting the data stored into ListViewItem
but when it's being displayed to the UI, it appears as
"ListViewItem {"name..."}"
instead of
"[ ] | First Name Last Name | active directory name | roleID"
You're seeing that because when you execute the following line:
checkedListBox1.Items.Add(lvi, true);
It's implicitly calling lvi.ToString(), which is displaying the name of the class.
Try this instead:
checkedListBox1.Items.Add(string.Join(" | ",
lvi.SubItems.Cast<ListViewItem.ListViewSubItem>().Select(x => x.Text)));
Also, I assume you're setting the MultiColumn property on the CheckedListBox to true. That does not lay things out nicely formatted, like in a grid. It just determines whether or not items display in a single column or flow into multiple columns as space permits.
MultiColumn = false:
MultiColumn = true:
You might be able to attain a quasi-table layout by using tabs, but it may look funny if some strings are much longer than the rest.
checkedListBox1.Items.Add(string.Join("\t",
lvi.SubItems.Cast<ListViewItem.ListViewSubItem>().Select(x => x.Text)));
You could probably get around that by finding the longest probable string and padding the Text property accordingly:
checkedListBox1.Items.Add(string.Join("",
lvi.SubItems.Cast<ListViewItem.ListViewSubItem>()
.Select(x => x.Text.Padding(20, ' ')));

How to show all data results to listview?

I have a code here showing the data from sqldatabase to listview when searching.
int flag = 0;
connectionstatus();
SqlCommand cmd = new SqlCommand("SELECT *FROM SampleDatabase WHERE IdNo=#IdNo", conn);
cmd.Parameters.Add("#IdNo", SqlDbType.VarChar).Value = txtIdNo.Text;
SqlDataReader objRead = cmd.ExecuteReader();
lvlist.Items.Clear();
while (objRead.Read())
{
if ((txtIdNo.Text) == (objRead["IdNo"].ToString()))
{
flag = 1;
break;
}
}
if (flag == 1)
{
ListViewItem list = new ListViewItem(basa["FID"].ToString());
list.SubItems.Add(objRead["FullName"].ToString());
list.SubItems.Add(objRead["Age"].ToString());
list.SubItems.Add(objRead["Gender"].ToString());
list.SubItems.Add(objRead["Relationship"].ToString());
list.SubItems.Add(objRead["SkillnOccupation"].ToString());
lvlist.Items.AddRange(new ListViewItem[] { list });
}
My problem is that when im searching and the database have data with the same IdNo it only shows 1 result. How can i show all the results that has the same IdNo? Can you guys help me out in this. Thanks in advance.
Put the item population code inside the loop:
while (objRead.Read())
{
ListViewItem list = new ListViewItem(basa["FID"].ToString());
list.SubItems.Add(objRead["FullName"].ToString());
list.SubItems.Add(objRead["Age"].ToString());
list.SubItems.Add(objRead["Gender"].ToString());
list.SubItems.Add(objRead["Relationship"].ToString());
list.SubItems.Add(objRead["SkillnOccupation"].ToString());
lvlist.Items.Add(list);
}
Replace your last line with this. Seems like you're making two ListViewItems for every item? See if it helps, then look here.
Add item to Listview control
lvlist.Items.Add(list);

Use switch statement inside foreach?

in this scenario I'm dealing with two gridviews (gvSnacks and gvSnackCart). gvSnacks contains a fixed list of items with a template button column to "add" the item to gvSnackCart.
The foreach comes into play because I want to make sure that the item hasn't already been placed in the cart. If the user selects an item twice, I want to execute a sql command and make the gvSnackCart quantity of that item go up by 1 (instead of generating a new record).
If the record isn't in the gvSnackCart, the foreach should loop all the way to its default and insert it.
Here's the sql command to insert
string sqlInsert = "INSERT INTO ShoppingCart…
([shopperID], [itemName], [itemType], [quantityOrdered], [unitPrice])…
VALUES (#shopperID, #itemName, #itemType, #quantityOrdered, #unitPrice)";
myCommand.Parameters.Add("#shopperID", System.Data.SqlDbType.NVarChar).Value = txtCurrentUser.Text;
myCommand.Parameters.Add("#itemName", System.Data.SqlDbType.NVarChar).Value = snackDescription;
myCommand.Parameters.Add("#itemType", System.Data.SqlDbType.NVarChar).Value = "snack";
myCommand.Parameters.Add("#quantityOrdered", System.Data.SqlDbType.Int).Value = 1;
myCommand.Parameters.Add("#unitPrice", System.Data.SqlDbType.Money).Value = snackPrice;`
SqlCommand myCommand = new SqlCommand(sqlInsert, myConnection);`
Now I get the selected item's name from gvSnacks, and compare with each one present inside gvSnackCart
// Retrieve item's name
int index = Convert.ToInt32(e.CommandArgument);
GridViewRow row = gvSnacks.Rows[index];
string snackDescription = row.Cells[2].Text.ToString();
// Checks for duplicate snack listing
int duplicate = 0;
foreach (GridViewRow gvRowSnack in gvSnackCart.Rows)
{
if (gvRowSnack.Cells[1].Text.ToString() == snackDescription)
{
duplicate = 1;
}
switch (duplicate)
{
case 0:
break;
case 1:
//This is the case where it's a duplicate
//and will be a command to update the record
break;
default:
try
{
myConnection.Open();
myCommand.ExecuteNonQuery();
myConnection.Close();
}
catch (Exception ex)
{
lblError.Visible = true;
lblError.Text = "There was an error while adding the records" + "<br />" + ex.Message;
}
break;
}
}
The gvSnackCart is databound and should update with a new item, unless its a duplicate where it'd do an update. For some reason however it is not functioning. I am not getting an error at runtime. I have tested a read/write with a label so I know I'm retrieving the item name from gvSnacks. I'm also checking the database table and it's not showing any records being added. What seems wrong?
You can spare yourself a lot of hassle by using LINQ:
foreach (var snacks in gvSnackCart.Rows.GroupBy(snack => snack.Cells[1].Text.ToString()))
{
var p = myCommand.Parameters;
// I'm largely guessing at these, but hopefully you get the idea.
p.Add("#shopperID" , SqlDbType.NVarChar).Value = txtCurrentUser.Text;
p.Add("#itemName" , SqlDbType.NVarChar).Value = snacks.Key;
p.Add("#itemType" , SqlDbType.NVarChar).Value = /* ??? */;
p.Add("#quantityOrdered", SqlDbType.Int ).Value = snacks.Count();
p.Add("#unitPrice" , SqlDbType.Money ).Value = snacks.Sum(r => r.SnackPrice);
…
}

Categories