Struggling in updating data in DataGridView - c#

I have a datagridview and it is bound to a database. When i click one of its cell to update its value, actually what happens is that the value of that particular cell is updated but the values of the same row is also updated to null. What do i do so that the values of the same row does not updates to null but it remains as they are?
My Code :
int quantityColumnIndex = 0;
string particularColumnIndex = "";
int rateColumnIndex = 0;
private void buttonUpdate_Click(object sender, EventArgs e)
{
{
string SQL = "Update OrderLineItems set Quantity = " + quantityColumnIndex +
", Particular = '" + particularColumnIndex +
"', Rate = " + rateColumnIndex + " where OrderLineItems.Id = " + Id;
result = dm.ExecuteActionQuery(SQL);
}
if (result > 0)
{
MessageBox.Show("Record Updated Successfully", "Update Record", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
private void dataGridViewOrderDetails_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == 1)
{
quantityColumnIndex = Convert.ToInt32(dataGridViewOrderDetails.Rows[e.RowIndex].Cells[e.ColumnIndex].Value);
}
if (e.ColumnIndex == 2)
{
particularColumnIndex = dataGridViewOrderDetails.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString();
}
if (e.ColumnIndex == 3)
{
rateColumnIndex = Convert.ToInt32(dataGridViewOrderDetails.Rows[e.RowIndex].Cells[e.ColumnIndex].Value);
}
}
Help required

One solution is to change quantityColumnIndex, particularColumnIndex and rateColumnIndex to nullables and change the query so it doesn't update the columns that weren't changed.
I guess you know which is the row that's being edited. If you don't, then you will have troubles if the user changes the values but selects another row. So, if you know the row, I think the better choice is to change the query to:
var row = dataGridViewOrderDetails.Rows[rowNumber];
string SQL = "Update OrderLineItems set Quantity = " + Convert.ToInt32(row.Cells[1].Value); + ", Particular = '" + row.Cells[2].Value.ToString() + "', Rate = " + Convert.ToInt32(row.Cells[e.ColumnIndex].Value)+ " where OrderLineItems.Id = " + Id;
result = dm.ExecuteActionQuery(SQL);

Have you tried to assign a new value ?
if (e.ColumnIndex == 1)
{
dataGridViewOrderDetails.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = 5;
}
However if the datagrid is bound to a datatable you have to update the value in the datatable.

Why are you casting the result of the Value property to the DataGridViewCell type? The Value property gives you the value of the cell, not the cell itself. The code is wrong; make sure you understand the object model of the DataGridView control.
Try the following code instead:
if (e.ColumnIndex == 1)
{
// Get a reference to the cell of interest.
DataGridViewCell quantity = dataGridViewOrderDetails.Rows[e.RowIndex].Cells[e.ColumnIndex];
// Update its value.
quantity.Value = 100; // or whatever your new value is
}

Can you check whether the same thing happening in your database as well ( changing all values to null except the one you edited).
Check the values of the variables(quantityColumnIndex,particularColumnIndex and rateColumnIndex ) at run time on line "result = dm.ExecuteActionQuery(SQL);".
I think all the values will be null except the one you just edited because you are changing the value of only one variable in dataGridViewOrderDetails_CellValueChanged(..) method. So you need to assign values to all the variables in the dataGridViewOrderDetails_CellValueChanged function.

private void buttonUpdate_Click(object sender, EventArgs e)
{
if ((dataGridViewOrderDetails.Rows.Count - 1 > RowCount) == false)
{
for (int i = 0; i < dataGridViewOrderDetails.RowCount - 1; i++)
{
string SQL = "Update OrderLineItems set Quantity = " + dataGridViewOrderDetails.Rows[i].Cells[1].Value +
", Particular = '" + dataGridViewOrderDetails.Rows[i].Cells[2].Value + "', Rate = " + dataGridViewOrderDetails.Rows[i].Cells[3].Value + " where OrderLineItems.Id = " + dataGridViewOrderDetails.Rows[i].Cells[0].Value;
result = dm.ExecuteActionQuery(SQL);
}
}
There is a problem in a query. This has been solved :)

Related

How to print only the specified rows from the grid view

Welcome
I have a sales screen with an invoice that is displayed in the grid view with the report of Extra Robert
I just want when I select some rows using the select box only the selected rows are printed on one page I tried this code but it prints each row in a separate report
I just want to print the selected rows on one page. Thank you
for (int i = 0; i <= DgvSale.Rows.Count - 1; i++)
{
if (Convert.ToBoolean(DgvSale.Rows[i].Cells[8].Value) == true)
{
tblRpt1 = db.readData("SELECT [Order_ID] as 'رقم الفاتورة',talb_ID as 'طلب',[Cust_Name] as 'اسم العميل',Products.Pro_Name as 'المنتج',Products.Group_ID as 'قسم',Products_Group.Group_Name as 'اسم القسم',[Sales_Detalis].[Qty] as 'الكمية',[Price] as 'السعر',[User_Name] as 'الكاشير',[Date] as 'التاريخ',[Unit] as 'الوحدة',[Sales_Detalis].Tax_Value as 'الضريبة',Price_Tax as 'السعر بعد الضريبة',[typetalab] as 'نوع الطلب',[priceservic] as 'خدمة',[shiftname] as 'شيفت',notes as 'ملاحظات',shiftnum as 'شيفت رقم',Print_Group.Print_Name,Print_Group.Name_Group FROM [dbo].[Sales_Detalis] , Products,Products_Group,Print_Group where Products.Pro_ID = Sales_Detalis.Pro_ID and Products.Pro_ID= " + row1.Cells[0].Value + " and Order_ID = " + id + " and Products.Group_ID = Products_Group.Group_ID and Print_Group.Name_Group=Products.Group_ID ORDER BY Order_ID ASC", "");
}
}
if (Properties.Settings.Default.SalePrintKind == "8CM")
{
devOrderSales2 rpt = new devOrderSales2() { DataSource = tblRpt1, DataMember = "OrderSales2" };
rpt.DataSource = tblRpt1;
rpt.Parameters["ID1"].Value = id;
rpt.PrinterName = Properties.Settings.Default.PrinterNameSteker;
rpt.xrTableCell8.Visible=true;
if (Properties.Settings.Default.saleprintauto == "0")
{
rpt.Print();
}
else if (Properties.Settings.Default.saleprintauto == "1")
{
rpt.ShowPreviewDialog();
}
}
I suggest to create the WHERE condition dynamically with the selected records:
string sql = #"SELECT [Order_ID] as 'رقم الفاتورة',talb_ID as 'طلب',[Cust_Name] as 'اسم العميل',Products.Pro_Name as 'المنتج',Products.Group_ID as 'قسم',Products_Group.Group_Name as 'اسم القسم',[Sales_Detalis].[Qty] as 'الكمية',[Price] as 'السعر',[User_Name] as 'الكاشير',[Date] as 'التاريخ',[Unit] as 'الوحدة',[Sales_Detalis].Tax_Value as 'الضريبة',Price_Tax as 'السعر بعد الضريبة',[typetalab] as 'نوع الطلب',[priceservic] as 'خدمة',[shiftname] as 'شيفت',notes as 'ملاحظات',shiftnum as 'شيفت رقم',Print_Group.Print_Name,Print_Group.Name_Group
FROM
[dbo].[Sales_Detalis]
INNER JOIN Products
ON Products.Pro_ID = Sales_Detalis.Pro_ID
INNER JOIN Products_Group
ON Products.Group_ID = Products_Group.Group_ID
INNER JOIN Print_Group
ON Print_Group.Name_Group=Products.Group_ID
WHERE
Products.Pro_ID IN ({0}) AND Order_ID = {1}
ORDER BY Order_ID ASC";
var productIds = new List<int>();
for (int i = 0; i <= DgvSale.Rows.Count - 1; i++) {
if (Convert.ToBoolean(DgvSale.Rows[i].Cells[8].Value) == true) {
productIds.Add(Convert.ToInt32(DgvSale.Rows[i].Cells[0].Value));
}
}
if (Properties.Settings.Default.SalePrintKind == "8CM" && productIds.Count > 0) {
string commandText = String.Format(sql, String.Join(", ", productIds), id);
tblRpt1 = db.readData(commandText, "");
var rpt = new devOrderSales2 {
DataSource = tblRpt1,
DataMember = "OrderSales2",
PrinterName = Properties.Settings.Default.PrinterNameSteker
};
rpt.xrTableCell8.Visible = true;
rpt.Parameters["ID1"].Value = id;
if (Properties.Settings.Default.saleprintauto == "0") {
rpt.Print();
} else if (Properties.Settings.Default.saleprintauto == "1") {
rpt.ShowPreviewDialog();
}
}
Also, you should use the modern JOIN syntax instead of the outdated join conditions in the WHERE clause.
Note that I have set up a SQL string with {0} and {1} as placeholders later being replaced with the String.Format method. I assumed the product ids to be of type int. The resulting WHERE conditions looks something like this:
WHERE
Products.Pro_ID IN (12, 30, 55, 68) AND Order_ID = 17
The C# verbatim strings introduced with #" allow you to include line breaks within the string and to make the SQL text more readable.
row1 always points to the same row. Get the row dynamically with DgvSale.Rows[i] instead, within the loop.
One way is to first collect all the relevant IDs from the rows, and only do 1 db query, eg:
var toprint_ids = new List<long>();
for (int i = 0; i <= DgvSale.Rows.Count - 1; i++)
{
if (Convert.ToBoolean(DgvSale.Rows[i].Cells[8].Value) == true)
{
var itm_id = Convert.ToInt64(row1.Cells[0].Value);
ids.Add(itm_id);
}
}
if (toprint_ids.Count == 0)
return;
tblRpt1 = db.readData("SELECT [Order_ID] as 'رقم الفاتورة',talb_ID as 'طلب',[Cust_Name] as 'اسم العميل',Products.Pro_Name as 'المنتج',Products.Group_ID as 'قسم',Products_Group.Group_Name as 'اسم القسم',[Sales_Detalis].[Qty] as 'الكمية',[Price] as 'السعر',[User_Name] as 'الكاشير',[Date] as 'التاريخ',[Unit] as 'الوحدة',[Sales_Detalis].Tax_Value as 'الضريبة',Price_Tax as 'السعر بعد الضريبة',[typetalab] as 'نوع الطلب',[priceservic] as 'خدمة',[shiftname] as 'شيفت',notes as 'ملاحظات',shiftnum as 'شيفت رقم',Print_Group.Print_Name,Print_Group.Name_Group FROM [dbo].[Sales_Detalis] , Products,Products_Group,Print_Group where Products.Pro_ID = Sales_Detalis.Pro_ID and Products.Pro_ID in (" + string.Join(",", toprint_ids) + ") and Order_ID = " + id + " and Products.Group_ID = Products_Group.Group_ID and Print_Group.Name_Group=Products.Group_ID ORDER BY Order_ID ASC", "");
if (Properties.Settings.Default.SalePrintKind == "8CM")
{
devOrderSales2 rpt = new devOrderSales2() { DataSource = tblRpt1, DataMember = "OrderSales2" };
rpt.DataSource = tblRpt1;
rpt.Parameters["ID1"].Value = id;
rpt.PrinterName = Properties.Settings.Default.PrinterNameSteker;
rpt.xrTableCell8.Visible=true;
if (Properties.Settings.Default.saleprintauto == "0")
{
rpt.Print();
}
else if (Properties.Settings.Default.saleprintauto == "1")
{
rpt.ShowPreviewDialog();
}
}
Please notice the change in the query as well: in (" + string.Join(",", toprint_ids) + ")
Also if you have non-numeric IDs for your rows (eg Guids), then you need to change the list to a List<string> and also change your query to like in ('" + string.Join("','", toprint_ids) + "')

Changing a value when a user change a value in the datagridview

I have two identical DataGridView, both have the same Properties, and same Events. But one of them is not changing the value when a user change value inside the DataGridView.
This are my DataGridView events
DataGridView dgvselect;
Label totAmt;
Label totItem;
private void dataGridRight_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
if (tabRight.SelectedTab == tabCart)
{
dgvselect = dataGridSales;
totAmt = lblSTotAmt;
totItem = lblSTotItem;
dataGridSales.BeginEdit(true);
}
if (tabRight.SelectedTab == tabEsti)
{
dgvselect = dataGridEsti;
totAmt = lblETotAmt;
totItem = lblETotItem;
dataGridEsti.BeginEdit(true);
}
}
private void dataGridRight_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
int lastqty = Convert.ToInt32(dgvselect.SelectedRows[0].Cells[6].Value.ToString());
int lessqty = Convert.ToInt32(dgvselect.SelectedRows[0].Cells[1].Value.ToString());
string part = dgvselect.SelectedRows[0].Cells[5].Value.ToString();
int nqty = lastqty - lessqty;
if (lessqty <= lastqty)
{
using (SqlConnection conn = new SqlConnection(#"Server=" + ip + "," + port + "; Database=records; User ID=" + sqlid + "; Password=" + sqlpass + ""))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(#"UPDATE [dbo].[products]
SET Stock = '" + nqty + "' WHERE [Part No.] = '" + part + "'", conn))
{
cmd.ExecuteNonQuery();
}
conn.Close();
}
scrollIndex = dataGridSrch.SelectedRows[0].Index;
scrollPos = dataGridSrch.FirstDisplayedScrollingRowIndex;
searchProd();
if (e.ColumnIndex == 1)
{
int qty = Convert.ToInt32(dgvselect.Rows[e.RowIndex].Cells[1].Value);
double price = Convert.ToDouble(dgvselect.Rows[e.RowIndex].Cells[4].Value);
dgvselect.Rows[e.RowIndex].Cells[3].Value = qty * price;
}
if (e.ColumnIndex == 3)
{
double price = Convert.ToDouble(dgvselect.Rows[e.RowIndex].Cells[3].Value);
dgvselect.Columns[3].ValueType = typeof(Double);
}
dgvselect.Columns[3].DefaultCellStyle.FormatProvider = CultureInfo.GetCultureInfo("en-PH");
dgvselect.Columns[3].DefaultCellStyle.Format = String.Format("C");
}
else
{
MessageBox.Show("Exceeds the amount of stock available", "Invalid Purchase", MessageBoxButtons.OK);
dgvselect.Rows[e.RowIndex].Cells[1].Value = 1;
}
}
private void dataGridRight_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
if (tabRight.SelectedTab == tabSales || tabRight.SelectedTab == tabEsti)
{
int count = 0;
double total = 0;
if (e.ColumnIndex == 1)
{
foreach (DataGridViewRow row in dgvselect.Rows)
{
count += Convert.ToInt32(row.Cells[1].Value);
}
totItem.Text = "Total Items: " + count;
}
if (e.ColumnIndex == 3)
{
foreach (DataGridViewRow row in dgvselect.Rows)
{
total += Convert.ToDouble(row.Cells[3].Value);
}
totAmt.Text = "Total Amount: " + total.ToString("C2");
}
amount = total;
}
}
When the user double clicks the cell, it will start editing and set the dgvselect, totAmt, and totItem values to its corresponding DataGridView and Labels
But when testing the app, the Cart tab page is not firing.
This is the initial values when an item is added inside the DataGridView. No changes are made for the Qty and Price.
But when there are some changes,
The totAmt and totItem texts didn't change. It will only change when an item is added.
As for the Estimate tab page, it can change the text values of totAmt and totItem.
I have tried copying the DataGridView in Estimate tab page and pasted it in Cart tab page.

C# Selecting multiple results in a listbox search?

I want to search a listbox for a object value i made. This is the override string. This is how items are added into the listbox.
public override string ToString()
{
string reservatiestring;
reservatiestring ="Kamer: " + roomNumber + " Op datum: " + datum + " Aantal personen: " + personen.Count + " Naam: " + reservatienaam;
return reservatiestring;
}
I'd now like to search in my listbox for results while searching for a specific roomNumber. All the roomNumbers are saved in a combobox. This is what i have currently:
private void buttonSearch_Click(object sender, EventArgs e)
{
foreach (var item in listBox1.Items)
{
for (int i = listBox1.Items.Count - 1; i >= 0; i--)
{
if (listBox1.Items[i].ToString().ToLower().Contains(comboBox1.SelectedText.ToLower()))
{
listBox1.SetSelected(i, true);
}
else
{
MessageBox.Show("error");
}
}
This only selects one result though and its not specified to the roomNumber object only. When i put in the foreach to make it select multiple items, my program failed and i got the following error:
The list that this enumerator is bound to has been modified. An enumerator can only be used if the list is not changed
Extra info as asked for!
This is where i add the info to the listbox:
private void btnReserve_Click(object sender, EventArgs e)
{
Reservations reservatie = new Reservations();
reservatie.roomNumber = Convert.ToInt32(numericUpDownroom.Value);
reservatie.datum = dateTimePicker1.Value;
reservatie.reservatienaam = textBoxName1.Text;
for (int i = 0; i <= personcount; i++)
{
Person persoon = new Person();
persoon.naam = textBoxName1.Text;
persoon.leeftijd = Convert.ToInt32(numericUpDownAge1.Value);
reservatie.personen.Add(persoon);
}
if (!comboBox1.Items.Contains(reservatie.roomNumber))
{
comboBox1.Items.Add(reservatie.roomNumber);
}
else
reservaties.Add(reservatie);
listBox1.FormattingEnabled = false;
listBox1.Items.Add(reservatie.ToString());
The error: the error when it pops up. The dutch additional information is the initial error message.
I don't see why you need a foreach to multi select in your case especially that you are not using the "var item" anywhere in the code.
However, the exception might happen if the "SetSelected" implementation is doing some changes internally to the items.
Make sure you have configured your list for multi-select
// Set the selection mode to multiple and extended.
listBox1.SelectionMode = SelectionMode.MultiExtended;
Remove the foreach. (If you still need another loop, replace your foreach with a "for")
Check the below documentation link which has v. good example of multi-select ListBox:
https://msdn.microsoft.com/en-us/library/system.windows.forms.listbox.items(v=vs.110).aspx

Finding specific value within a loop

I'm using an Enum within a ComboBox. I want it to allow editing, so that the user can type things in it. I converted the Enum to a string[] arrayItems while listItems is the length of the Enum list.
Now I want to check the users text input: If it isn't listed, it should show a message that the item is not listed there.
But for my code (below) it shows me a error multiple times:
// Converted enum to string[] before
for (int i = 0; i < listItems; i++)
{
if (comboBox1.Text != arrayItems[i])
{
message = string.Format("Sorry! " + comboBox1.Text + " not found.");
}
}
This shows error every time I start it as it iterates through each and every element in the list. I want that if this could check the whole Enum list and give the error once in case of wrong input.
You can change your loop as
bool ok = false;
for (int i = 0; i < listItems; i++)
{
if (comboBox1.Text == arrayItems[i])
{
ok=true;
break;
}
}
if(ok==false)
{
message = string.Format("Sorry! " + comboBox1.Text + " not found.");
}
if(arrayItrmd.Contains(combobox1.Text))
{
//logic if trur
}
You can use LINQ's All for this. As the name implies, it will only be true if all elements correspond to your query. It's basically the equivalent of !Any
if (arrayItrmd.All(item => item != comboBox1.Text))
{
message = string.Format("Sorry! " + comboBox1.Text + " not found.");
}
This means "If each element from arrayItrmd is not equal to comboBox1's text, assign the message."
You can ignore the use of a loop
if(tmpImageArray.FirstOrDefault(a => a == comboBox1.Text) == default(String))
{
message = comboBox1.Text + " not found";
}
else{
message = comboBox1.Text + " found";
}
I have solved this problem like this,
First my enum that I will bind to my combobox
public enum comboboxVals
{
one, two, three
}
Then set my combobox's datasource like this
comboBox1.DataSource = Enum.GetNames(typeof(comboboxVals));
and then implemented code in one of my combobox events to check if the value is valid like combobox Leave, Validating and Validated events..
private void comboBox1_Validating(object sender, CancelEventArgs e)
{
var cbx = sender as ComboBox;
if (!Enum.IsDefined(typeof(comboboxVals), cbx.Text))
{
MessageBox.Show(cbx.Text + " not in the list");
e.Cancel=true;
}
else
{
// Implement your logic here
}
}

'Find' button which can count the number of rows in a table, which consist of DateTime

I'm new in c#.
I need to add a Find_Click button which has the functions that can help me to count the number of Rows in a database Table when l key in the value inside the textbox, then display the counted value.
The problem is, the number of rows could not be counted because the values inside are Datetime.
Could anyone help me fix my code? Here it is:
private void Find_Click(object sender, EventArgs e)
{
string search = FindDateTime.Text;
int result = 0;
DataRow[] returnedRows;
returnedRows = RetailCamDataSet1.Tables["pcPeopleCountingValue"]
.Select("ValueDateTime='" + search + "'");
result = returnedRows.Length;
if (result > 0)
{
DataRow RetailCamDataRow1;
RetailCamDataRow1 = returnedRows[0];
MessageBox.Show(returnedRows.Length.ToString());
}
else
{
MessageBox.Show("No such Record.");
}
}
The following line should change to this:
returnedRows = RetailCamDataSet1.Tables["pcPeopleCountingValue"]
.Select("ValueDateTime=#" + search + "#");
Provided your search variable has the DateTime in the right format.
From your comment. You can't use BETWEEN in the Select() method, instead you could do something like:
RetailCamDataSet1.Tables["pcPeopleCountingValue"]
.Select("ValueDateTime < #" + search" +
"00:00:00# AND ValueDateTime < #" + search + "23:59:59#");
You could also use dataset lambda extensions, see : https://stackoverflow.com/a/3924140/368070

Categories