So I'm creating a project, which is a Point of Sale, like those in fast food chains.
The buttons on my POS is created dynamically, depends on the values from my database, and now I'm having a hard time to compute the subtotal when I change the quantity of each item. I used DataGrid to list all the products ordered by the customer.
I created two buttons which is add and minus that can set the quantity of the selected row in the datagridview, I'm not sure if I got it right but the code is also provided below which computes the price of the selected item multiplied to the quantity.
My problem is, how can I compute the subtotal price, and the total quantity of items in my datagridview everytime I add items in my datagrid or I add or subtract in the quantity of the item.? The subtotal should reflect immediately EVERYTIME I add an item, or add or subtract an item.
Provided is a sample image to understand better what I want to happen in my project.
public void quantity_change(object sender, EventArgs e)
{
var row = dataGridView1.CurrentRow;
if (row == null || row.Index < 0)
return;
var unit = (sender == add) ? 1 : -1;
var quantity = Convert.ToInt32(row.Cells["Quantity"].Value) + unit;
row.Cells["Quantity"].Value = quantity;
var rate = Convert.ToDouble(row.Cells["SellingPrice"].Value);
row.Cells["TotalPrice"].Value = quantity * rate;
}
private void frmPOS_Load(object sender, EventArgs e)
{
dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
add.Click += quantity_change;
minus.Click += quantity_change;
cmd = new MySqlCommand("SELECT * FROM tblmenu", dbConn);
MySqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
Button btn = new Button();
btn.Text = rdr["menuName"].ToString();
btn.Name = rdr["menuID"].ToString();
btn.Width = 126;
btn.Height = 80;
btn.Click += delegate
{
dataGridView1.ClearSelection();
MySqlConnection cnn2 = new MySqlConnection(sqlConn.connString);
cnn2.Open();
cmd = new MySqlCommand("SELECT menuName, menuPrice FROM tblmenu WHERE menuID = #id", cnn2);
cmd.Parameters.AddWithValue("#id", btn.Name);
MySqlDataReader rdr2 = cmd.ExecuteReader();
while (rdr2.Read())
{
//I added the item in my datagridview, with the button name, 1 = 1quantity, and Selling Price
dataGridView1.Rows.Add(rdr2.GetString("menuName").ToUpper(), 1, rdr2.GetDouble("menuPrice"));
}
//I copied the value of Selling Price Column to the Total Price Column in this part
foreach (DataGridViewRow row in dataGridView1.Rows)
{
value = row.Cells["SellingPrice"].Value.ToString();
row.Cells["TotalPrice"].Value = value;
}
};
if (rdr["menuAvailability"].ToString() == "yes")
{
if (rdr["menuCategory"].ToString() == "Sandwiches")
{
flpSandwiches.Controls.Add(btn);
}
else if (rdr["menuCategory"].ToString() == "Appetizers")
{
flpAppetizers.Controls.Add(btn);
}
}
}
rdr.Close();
}
What I can see in your quantity_change method:
row.Cells["TotalPrice"].Value = quantity * rate;
for me it is subtotal for given product.
You you wan't to calculate total price of whole order (all products in data grid) you need to sum all subtotals for all products.
For example, at the end of quantity_Change:
double Total=0;
foreach (DataGridViewRow row in dataGridView1.Rows)
{
Total+=row.Cells["TotalPrice"].Value;
}
// now you can set this value for example label under data grid
labelTotal.Text = Total.ToString();
Related
I just want to ask how I can update or change the cell value of column 'quantity' in my DataGridView when I select a certain row.
I have 3 columns in my DataGridView which are Item Name, Quantity and Price.
Every time I click the button 'add' or 'less' on my form, the quantity of the selected row item will either add to or subtract 1 from the quantity column and the price will also update every time the quantity increments or decrements. Here is my code when I add my item to my DataGridView.
I'm not really sure if I got it right to add items to my datagrid.
cmd = new MySqlCommand("SELECT * FROM tblmenu", dbConn);
MySqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
Button btn = new Button();
btn.Text = rdr["menuName"].ToString();
btn.Width = 126;
btn.Height = 80;
btn.Click += delegate
{
MySqlConnection cnn2 = new MySqlConnection(sqlConn.connString);
cnn2.Open();
cmd = new MySqlCommand("SELECT menuName, menuPrice FROM tblmenu WHERE menuName = #name", cnn2);
cmd.Parameters.AddWithValue("#name", btn.Text);
MySqlDataReader rdr2 = cmd.ExecuteReader();
while (rdr2.Read())
{
dataGridView1.Rows.Add(rdr2.GetString("menuName").ToUpper(), 1, rdr2.GetDouble("menuPrice"));
}
dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
lblQty.Text = dataGridView1.RowCount.ToString();
};
}
I have tried this but when I click another set of item, the quantity from the previous selected item still increments.
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
Add.Click += delegate
{
dataGridView1.Rows[e.RowIndex].Cells["quantity"].Value = Convert.ToInt32(dataGridView1.Rows[e.RowIndex].Cells["quantity"].Value) + 1;
};
Minus.Click += delegate
{
dataGridView1.Rows[e.RowIndex].Cells["quantity"].Value = Convert.ToInt32(dataGridView1.Rows[e.RowIndex].Cells["quantity"].Value) - 1;
};
}
I suggest you consider binding your DataGridView to a data source. You should not perform data operations on the UI if you can avoid it.
To demonstrate this,
private void quantityChangeClick(object sender, EventArgs e)
{
addToQuantity((Button)sender == this.Add ? 1 : -1);
updateTotal();
}
private void addToQuantity(int howMuch)
{
var selectedRowIndices = dataGridView1.SelectedRows.OfType<DataGridViewRow>().Select(ro => ro.Index);
this.rows.Where((r, i) => selectedRowIndices.Contains(i)).ToList().ForEach(
r => r.Quantity = Math.Max(0, r.Quantity + howMuch));
this.dataGridView1.Refresh();
}
// calculate the total from the data source as well
private void updateTotal()
{
var total = Math.Round(this.rows.Sum(r => r.Quantity * r.Price), 2, MidpointRounding.AwayFromZero);
this.TotalLabel.Text = string.Format("₱{0:0.00}", total);
}
I have used some dummy data to demo this on my end, that is the Row class. Actually, you could do a similar thing, and add a Row to the data source rows with each record from your database.
private class Row
{
public string ItemName { get; set; }
public int Quantity { get; set; }
public double Price { get; set; }
public Row(string i, int q, double p)
{
this.ItemName = i;
this.Quantity = q;
this.Price = p;
}
}
private List<Row> rows = new List<Row>();
private void Form1_Load(object sender, EventArgs e)
{
// instead, here you will add your rows from SQL
rows.AddRange(new Row[]
{
new Row("item1", 0, 500),
new Row("item2", 0, 400),
new Row("item3", 0, 850)
});
this.dataGridView1.DataSource = rows;
dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
Add.Click += quantityChangeClick;
Minus.Click += quantityChangeClick;
}
First of all, using dataGridView1_CellContentClick does not serve the purpose at all. You intend to increase or decrease quantity on Add or Minus button click. I would use dataGridView1.CurrentRow property to get hold of CurrentRow and manipulate quantity column.For updating price column, you should have a Rate column or a constant Rate value to multiply it with quantity. Do you have it? If not then I don't see how you arrive on price calculation. However assuming you have one :
void quantity_change(object sender, EventArgs e){
var row=dataGridView1.CurrentRow;
if(row==null || row.Index<0)
return;
var unit = (sender==add)?1:-1;
var quantity = Convert.ToInt32(row.Cells["quantity"].Value) + unit;
row.Cells["quantity"].Value = quantity;
//assuming you have rate column...
var rate = Convert.ToDouble(row.Cells["Rate"].Value);
row.Cells["Price"].Value = quantity * rate;
}
Now bind Click event of your Add & Minus Buttons to the method above in Form constructor.
public myForm(){
InitializeComponents();
Add.Click+=quantity_change;
Minus.Click+=quantity_change;
}
You can also use form's Load event if you want.
I have a datagridview with quantity and price and net price. By default quantity is 1 and the relevant price is there. I want to edit the quantity so net price will come according to that. For e.g if I edit quantity to 2 the netprice will come for 2. it will take price from price column and calculate
Here's my code.
private void grvItems_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
foreach (DataGridViewRow row in grvItems.Rows)
{
if (e.ColumnIndex == grvItems.Columns["Quantity"].Index)
{
grvItems.EndEdit();
decimal quantity = Convert.ToDecimal(row.Cells["Quantity"].Value);
decimal price = Convert.ToDecimal(row.Cells["Amt"].Value);
decimal netprice = (quantity * price);
row.Cells["netprice"].Value = Math.Round((netprice), 2);
}
}
CalculateTotal();
}
But the evnt is not firing. If i edit quantity, the net price is not relflected. Please suggest ideas.
Your change will reflect only after the cell will lost focus.
If you want to see the change during the edit, you can use the other event:
dataGridView1_CellBeginEdit
You can get help from MSDN, there is a good and simple example there: CellBeginEdit and CellEndEdit
UPDATE
As already mentioned, let's ensure you have registered your events.
In your form constructor, write as following:
public Form1() // Constructor
{
InitializeComponent();
grvItems.CellBeginEdit += grvItems_CellBeginEdit;
grvItems.CellEndEdit += grvItems_CellEndEdit;
}
UPDATE
It is hard to help you in that way. I have created a similar example. Open a new Windows Form application, paste the following code.
You need to add a DataGridView on the form (Form1).
This example is working fine. After doing it, try to see what are the differences with your code.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
System.Data.DataTable dt = new System.Data.DataTable();
dt.Columns.Add("Quantity", Type.GetType("System.Decimal")); // You can change it to Int32
dt.Columns.Add("Amt", Type.GetType("System.Decimal"));
dt.Columns.Add("netprice", Type.GetType("System.Decimal"));
var row = dt.NewRow();
row["Quantity"] = 1;
row["Amt"] = 2.5;
row["netprice"] = 0;
dt.Rows.Add(row);
dataGridView1.DataSource = dt;
}
private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
foreach (DataGridViewRow row in dataGridView1.Rows)
{
if (e.ColumnIndex == dataGridView1.Columns["Quantity"].Index)
{
dataGridView1.EndEdit();
decimal quantity = Convert.ToDecimal(row.Cells["Quantity"].Value);
decimal price = Convert.ToDecimal(row.Cells["Amt"].Value);
decimal netprice = (quantity * price);
row.Cells["netprice"].Value = Math.Round((netprice), 2);
}
}
// My suggestion:
// No need to go through all the rows, just the current one
/*
if (e.ColumnIndex == dataGridView1.Columns["Quantity"].Index)
{
// dataGridView1.EndEdit(); // No need this line, you are already in CellEndEdit event
var currentRow = dataGridView1.Rows[e.RowIndex];
decimal quantity = Convert.ToDecimal(currentRow.Cells["Quantity"].Value);
decimal price = Convert.ToDecimal(currentRow.Cells["Amt"].Value);
decimal netprice = (quantity * price);
currentRow.Cells["netprice"].Value = Math.Round((netprice), 2);
}
*/
}
}
You might want to try using the CellValueChanged event as an alternative to CellEndEdit and see if it does what you want.
Also, consider having the DataGridView do most of the work:
public partial class AlternativeToCellEndEdit : Form
{
public AlternativeToCellEndEdit()
{
InitializeComponent();
dataGridView1.CellValueChanged += DataGridView1_CellValueChanged;
}
// Try handling CellValueChanged instead of CellEndEdit
private void DataGridView1_CellValueChanged(Object sender, DataGridViewCellEventArgs e)
{
// Our MyRecord class is smart and makes the calculation
// any time we change Quantity or Amt. Here, we only need
// to refresh the DataGridView to show the updated info.
dataGridView1.Refresh();
}
// Make a class to represent a line item in the DataGridView.
// When the Quantity or Amt changes, it recalculates itself.
class MyRecord
{
public string Description { get; set; } = "New Item";
int mQuantity = 1;
public int Quantity
{
get { return mQuantity; }
set { mQuantity = value; NetPrice = Quantity * Amt; } // Recalc
}
double mAmt = 0.00;
public double Amt
{
get { return mAmt; }
set { mAmt = value; NetPrice = Quantity * Amt; } // Recalc
}
public double NetPrice { get; private set; } // Makes this cell Read-Only in the DataGridView
}
// Tell the DataGridView that we want to display our custom class.
BindingList<MyRecord> Items = new BindingList<MyRecord>();
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
// Bind data to the view.
// Now DataGridView does all the work for us.
dataGridView1.DataSource = Items;
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Make everything look nice in the way of formatting.
DataGridViewColumn col;
col = dataGridView1.Columns["Description"];
col.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
col = dataGridView1.Columns["Quantity"];
col.AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
col = dataGridView1.Columns["Amt"];
col.AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
col.DefaultCellStyle.Format = "F2";
col = dataGridView1.Columns["NetPrice"];
col.AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
col.DefaultCellStyle.Format = "F2";
// Add the first default item
Items.Add(new MyRecord());
}
}
I use a button on click event to add a product to my GridControl. On the event, theres a for-loop that calculates the items. My problem is when clicking the event, it adds the product to the grid, but it does not calculate the item.
I use a void method to calculate and call it with gridrowcount changed event, however, I don't want this. I want it to calculate when adding a product.
void Hesapla()
{
decimal Toplam = 0;
for (int i = 0; i < gridView1.RowCount + 1; i++)
{
Toplam += decimal.Parse(gridView1.GetRowCellValue(i, "Tpl").ToString());
}
txtToplam.Text = Toplam.ToString("0.00");
btnAdetText.Text = gridView1.RowCount.ToString() + " Ürün";
}
When I change RowCount to -1 or +1 it gives an error.
My code for adding a product:
SimpleButton urun = (SimpleButton)sender;
UrunID = Convert.ToInt16(urun.Tag);
DataRow Dr = cls.urunSec(UrunID);
Ses2();
gridView1.AddNewRow();
gridView1.SetRowCellValue(DevExpress.XtraGrid.GridControl.NewItemRowHandle, "ID", Dr["ID"].ToString());
gridView1.SetRowCellValue(DevExpress.XtraGrid.GridControl.NewItemRowHandle, "STOKADI", Dr["STOKADI"].ToString());
gridView1.SetRowCellValue(DevExpress.XtraGrid.GridControl.NewItemRowHandle, "ADET", Adet);
gridView1.SetRowCellValue(DevExpress.XtraGrid.GridControl.NewItemRowHandle, "TOPLAM", Dr["SATISFIYAT"].ToString());
private void urn_Click(object sender, EventArgs e)
{
// Hi
// ım add new product from here
SimpleButton urun = (SimpleButton)sender;
UrunID = Convert.ToInt16(urun.Tag);
DataRow Dr = cls.urunSec(UrunID);
Ses2();
gridView1.AddNewRow();
gridView1.SetRowCellValue(DevExpress.XtraGrid.GridControl.NewItemRowHandle, "ID", Dr["ID"].ToString());
gridView1.SetRowCellValue(DevExpress.XtraGrid.GridControl.NewItemRowHandle, "STOKADI", Dr["STOKADI"].ToString());
gridView1.SetRowCellValue(DevExpress.XtraGrid.GridControl.NewItemRowHandle, "MIKTAR", Adet);
gridView1.SetRowCellValue(DevExpress.XtraGrid.GridControl.NewItemRowHandle, "BIRIMFIYAT", Dr["SATISFIYAT"].ToString());
Hesapla();
}
I have added , but did not
I have a gridcontrol and in there unitPrice, TotalPrice and Quantity column. When i use this code to calculate unitPrice it calculates the first row and another rows in UnitPrice = 0 Please help?
private void Chillers_Load(object sender, EventArgs e)
{
this.ornekTblTableAdapter.Fill(this.chillersDataSet.OrnekTbl);
InitMDBData();
var row = gridView1.GetFocusedDataRow();
var totalprice = Convert.ToDecimal(row["TotalPrice"]);
var quantity = Convert.ToDecimal(row["Quantity"]);
row["UnitPrice"] = totalprice / quantity;
}
You need a simple foreach loop
foreach(var row in gridView1.Rows)
{
var totalprice = Convert.ToDecimal(row["TotalPrice"]);
var quantity = Convert.ToDecimal(row["Quantity"]);
row["UnitPrice"] = totalprice / quantity;
}
Update: for your special dataGridView try this:
for(int i=0; i< gridView1.RowCount; i++)
{
var totalprice = Convert.ToDecimal(gridView.GetRowCellValue(i, "TotalPrice"));
var quantity = Convert.ToDecimal(gridView.GetRowCellValue(i, "Quantity"));
gridView1.SetRowCellValue(i,"UnitPrice",(totalprice / quantity));
}
You are only changing one row, gridView1.GetFocusedDataRow().
You need to either add the computed value to the original data source, or put a data binding expression in your gridview markup, i.e.
<asp:templatecolumn><%# Eval(((decimal)Container.DataItem["TotalPrice"]) / ((decimal)Container.DataItem["TotalPrice"]) %></asp:templatecolumn>
I Have a DataGridView, with columns Item, description, quantity, rate & total.
I have two types of items, one item have vapasi == yes (vapasi is a kind of deposite amount), & another item have vapasi == No.I want to calculate the sum of 'total' column by differentiating items with vapasi & items without vapasi, & want to display this calculated total into two respective textboxes that is 'txtboxwithvapasi', n 'txtboxwithoutvapasi' which are there after the grid.I did following code :
private void grdPurchase_CellEndEdit_1(object sender, DataGridViewCellEventArgs e)
{
try
{
try
{
string value = grdPurchase.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString();
if (e.ColumnIndex == 2)
{
int val = int.Parse(value);
quantity = val;
}
if (e.ColumnIndex == 4)
{
float val = float.Parse(value);
total = val;
if (vapasi1 == "Yes")
{
vtot += total; //vtot=0+10
txt_forvapasitotal.Text = vtot.ToString(); //10
float vapsitot =float.Parse(txt_forvapasitotal.Text);
float vapsicalculate = (vapsitot * a);
float tax = vapsicalculate / 100;
float with_vapasi = vtot + tax;
txt_withvapasi.Text =Convert.ToString(with_vapasi);
}
else
{
nvtot = 0;
for (int i = 0; i < grdPurchase.Rows.Count; i++)
{
if (vapasi1 == "No")
{
if (grdPurchase.Rows[e.RowIndex].Cells[3].Selected == true)
{
nvtot += float.Parse(grdPurchase[4, i].EditedFormattedValue.ToString());
txt_withoutvapasitot.Text = nvtot.ToString();
}
}
}
}
txt_vapasiincludedtot.Text =(float.Parse(txt_withvapasi.Text) +float.Parse(txt_withoutvapasitot.Text)).ToString();
}
if (e.ColumnIndex == 1)
{
int val = int.Parse(value);
materialid = val;
string vapasi = "Select material_vapasi from tbl_material_master where active_flag=1 AND material_id =" + materialid + "";
SqlCommand cmd = new SqlCommand(vapasi, con);
sdr = cmd.ExecuteReader();
if (sdr.HasRows)
{
while (sdr.Read())
{
vapasi1 = sdr["material_vapasi"].ToString();
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message.ToString());
}
grdPurchase.Columns[3].ReadOnly = false;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message.ToString());
}
}
Problem is:-when I am selecting item with vapasi in first row & in second row item without vapasi , its working properly.But if i Select any item at third row ,then its doing sum of all the three items in 'txtboxwithoutvapasi' without differentiating items.
You need to keep track of vapasi being "Yes" or "No" for each row in the grid, but you are using a single variable. Can't you add this column to the grid (as a hidden column if you don't want to show this to the user)? Then whenever you need to calculate the totals you simply iterate through the grid rows and check the vapasi column in stead of the vapasi1 variable.