[英]Problem on adding quantity in existing item in DataGridView - vb.net
我正在创建一个购物系统作为我的大学迷你项目,用户可以在其中输入他们想要的商品的条形码,输入的商品将添加到右侧的网格中,也作为新商品添加到左侧的网格中。 每个项目都有一个唯一的条形码,并且可以有相同的产品代码。 当用户输入具有相同产品代码的项目时,数量将添加到左侧的网格中。 我遇到一个问题,当需要添加第二个项目数量时,系统将其检测为新项目而不是添加数量
例如:产品和项目的示例
Public Sub addRecordTo2ndDGV()
Try
dbconnection()
sql = "SELECT * FROM items_database WHERE Item_Barcode = @ItemBarcode;"
cmd = New MySqlCommand
With cmd
.Connection = conn
.CommandText = sql
.Parameters.Clear()
.Parameters.AddWithValue("@ItemBarcode", formUser.barcodeTB.Text)
End With
da = New MySqlDataAdapter
dt = New DataTable
da.SelectCommand = cmd
da.Fill(dt)
If dt.Rows.Count > 0 Then
Dim ItemProductCode, ItemBarcode As String
Dim repeated As Boolean = False
ItemProductCode = dt.Rows(0).Item(1)
ItemBarcode = dt.Rows(0).Item(2)
formUser.itemproductcodeTB.Text = ItemProductCode
formUser.itembarcodetb.Text = ItemBarcode
For Each row2 As DataGridViewRow In formUser.ItemBarcodeDGV.Rows
If Convert.ToString(row2.Cells(1).Value) = formUser.itembarcodetb.Text AndAlso Convert.ToString(row2.Cells(0).Value) = formUser.itemproductcodeTB.Text Then
MsgBox("QUANTITY WILL MINUS")
minusQuantity()
formUser.ItemBarcodeDGV.Rows.Remove(row2)
MsgBox("QUANTITY HAS MINUS")
Exit For
ElseIf Convert.ToString(row2.Cells(1).Value) <> formUser.itembarcodetb.Text AndAlso Convert.ToString(row2.Cells(0).Value) = formUser.itemproductcodeTB.Text Then
MsgBox("QUANTITY WILL ADD")
formUser.ItemBarcodeDGV.Rows.Add(New String() {formUser.itemproductcodeTB.Text, formUser.itembarcodetb.Text})
addQuantity()
MsgBox("QUANTITY HAS ADDED")
Exit For
ElseIf Convert.ToString(row2.Cells(1).Value) <> formUser.itembarcodetb.Text AndAlso Convert.ToString(row2.Cells(0).Value) <> formUser.itemproductcodeTB.Text Then
MsgBox("NEW ITEM")
formUser.ItemBarcodeDGV.Rows.Add(New String() {formUser.itemproductcodeTB.Text, formUser.itembarcodetb.Text})
addRecord()
MsgBox("REGISTERED SUCCESSFULL")
Exit For
End If
Exit For
Next
Else
MsgBox("Barcode not registered!")
formUser.barcodeTB.Text = ""
formUser.barcodeTB.Focus()
End If
Catch ex As Exception
MsgBox(ex.Message)
Finally
conn.Close()
da.Dispose()
formUser.barcodeTB.Text = ""
clearUserForm()
retrieveSubTotal()
End Try
End Sub
Public Sub addRecord()
If formUser.itemproductcodeTB.Text = "" Then
MsgBox("Scan a barcode")
Else
Try
dbconnection()
sql = "SELECT * FROM products_database WHERE Product_Code = @ProductCode;"
cmd = New MySqlCommand
With cmd
.Connection = conn
.CommandText = sql
.Parameters.Clear()
.Parameters.AddWithValue("@ProductCode", formUser.itemproductcodeTB.Text)
End With
da = New MySqlDataAdapter
dt = New DataTable
da.SelectCommand = cmd
da.Fill(dt)
If dt.Rows.Count > 0 Then
Dim productcode, itemdescription, unitprice As String
Dim repeated As Boolean = False
productcode = dt.Rows(0).Item(1)
itemdescription = dt.Rows(0).Item(3)
unitprice = dt.Rows(0).Item(4)
formUser.productcodeTB.Text = productcode
formUser.itemdescriptionTB.Text = itemdescription
formUser.unitpriceTB.Text = unitprice
formUser.unitQuantityTB.Text = "1"
For Each row As DataGridViewRow In formUser.ProductAddToCartDGV.Rows
If Convert.ToString(row.Cells(0).Value) = formUser.productcodeTB.Text AndAlso Convert.ToString(row.Cells(2).Value) = formUser.unitpriceTB.Text Then
row.Cells(4).Value = Convert.ToString(row.Cells(3).Value * row.Cells(2).Value)
End If
Next
formUser.ProductAddToCartDGV.Rows.Add(New String() {formUser.productcodeTB.Text, formUser.itemdescriptionTB.Text, formUser.unitpriceTB.Text, formUser.unitQuantityTB.Text, formUser.unitpriceTB.Text})
End If
Catch ex As Exception
MsgBox(ex.Message)
Finally
conn.Close()
da.Dispose()
End Try
End If
End Sub
Public Sub addQuantity()
If formUser.itemproductcodeTB.Text = "" Then
MsgBox("Scan a barcode")
Else
Try
dbconnection()
sql = "SELECT * FROM products_database WHERE Product_Code = @ProductCode;"
cmd = New MySqlCommand
With cmd
.Connection = conn
.CommandText = sql
.Parameters.Clear()
.Parameters.AddWithValue("@ProductCode", formUser.itemproductcodeTB.Text)
End With
da = New MySqlDataAdapter
dt = New DataTable
da.SelectCommand = cmd
da.Fill(dt)
If dt.Rows.Count > 0 Then
Dim productcode, itemdescription, unitprice As String
Dim repeated As Boolean = False
productcode = dt.Rows(0).Item(1)
itemdescription = dt.Rows(0).Item(3)
unitprice = dt.Rows(0).Item(4)
formUser.productcodeTB.Text = productcode
formUser.itemdescriptionTB.Text = itemdescription
formUser.unitpriceTB.Text = unitprice
formUser.unitQuantityTB.Text = "1"
For Each row As DataGridViewRow In formUser.ProductAddToCartDGV.Rows
If Convert.ToString(row.Cells(0).Value) = formUser.productcodeTB.Text AndAlso Convert.ToString(row.Cells(2).Value) = formUser.unitpriceTB.Text Then
row.Cells(3).Value = Convert.ToString(Convert.ToInt16(row.Cells(3).Value + 1))
row.Cells(4).Value = Convert.ToString(row.Cells(3).Value * row.Cells(2).Value)
End If
Next
End If
Catch ex As Exception
MsgBox(ex.Message)
Finally
conn.Close()
da.Dispose()
End Try
End If
End Sub
Public Sub minusQuantity()
If formUser.itemproductcodeTB.Text = "" Then
MsgBox("Scan a barcode")
Else
Try
dbconnection()
sql = "SELECT * FROM products_database WHERE Product_Code = @ProductCode;"
cmd = New MySqlCommand
With cmd
.Connection = conn
.CommandText = sql
.Parameters.Clear()
.Parameters.AddWithValue("@ProductCode", formUser.itemproductcodeTB.Text)
End With
da = New MySqlDataAdapter
dt = New DataTable
da.SelectCommand = cmd
da.Fill(dt)
If dt.Rows.Count > 0 Then
Dim productcode, itemdescription, unitprice As String
Dim repeated As Boolean = False
productcode = dt.Rows(0).Item(1)
itemdescription = dt.Rows(0).Item(3)
unitprice = dt.Rows(0).Item(4)
formUser.productcodeTB.Text = productcode
formUser.itemdescriptionTB.Text = itemdescription
formUser.unitpriceTB.Text = unitprice
formUser.unitQuantityTB.Text = "1"
For Each row As DataGridViewRow In formUser.ProductAddToCartDGV.Rows
If Convert.ToString(row.Cells(0).Value) = formUser.productcodeTB.Text AndAlso Convert.ToString(row.Cells(2).Value) = formUser.unitpriceTB.Text Then
row.Cells(3).Value = Convert.ToString(Convert.ToInt16(row.Cells(3).Value - 1))
row.Cells(4).Value = Convert.ToString(row.Cells(3).Value * row.Cells(2).Value)
End If
Next
End If
Catch ex As Exception
MsgBox(ex.Message)
Finally
conn.Close()
da.Dispose()
End Try
End If
End Sub
这是我的做法:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="ProdDataSet" targetNamespace="http://tempuri.org/ProdDataSet.xsd" xmlns:mstns="http://tempuri.org/ProdDataSet.xsd" xmlns="http://tempuri.org/ProdDataSet.xsd" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:msprop="urn:schemas-microsoft-com:xml-msprop" attributeFormDefault="qualified" elementFormDefault="qualified">
<xs:annotation>
<xs:appinfo source="urn:schemas-microsoft-com:xml-msdatasource">
<DataSource DefaultConnectionIndex="0" FunctionsComponentName="QueriesTableAdapter" Modifier="AutoLayout, AnsiClass, Class, Public" SchemaSerializationMode="IncludeSchema" xmlns="urn:schemas-microsoft-com:xml-msdatasource">
<Connections />
<Tables />
<Sources />
</DataSource>
</xs:appinfo>
</xs:annotation>
<xs:element name="ProdDataSet" msdata:IsDataSet="true" msdata:UseCurrentLocale="true" msprop:EnableTableAdapterManager="true" msprop:Generator_DataSetName="ProdDataSet" msprop:Generator_UserDSName="ProdDataSet">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="Products" msprop:Generator_TableClassName="ProductsDataTable" msprop:Generator_TableVarName="tableProducts" msprop:Generator_TablePropName="Products" msprop:Generator_RowDeletingName="ProductsRowDeleting" msprop:Generator_RowChangingName="ProductsRowChanging" msprop:Generator_RowEvHandlerName="ProductsRowChangeEventHandler" msprop:Generator_RowDeletedName="ProductsRowDeleted" msprop:Generator_UserTableName="Products" msprop:Generator_RowChangedName="ProductsRowChanged" msprop:Generator_RowEvArgName="ProductsRowChangeEvent" msprop:Generator_RowClassName="ProductsRow">
<xs:complexType>
<xs:sequence>
<xs:element name="Id" msprop:Generator_ColumnVarNameInTable="columnId" msprop:Generator_ColumnPropNameInRow="Id" msprop:Generator_ColumnPropNameInTable="IdColumn" msprop:Generator_UserColumnName="Id" type="xs:int" />
<xs:element name="Name" msprop:Generator_ColumnVarNameInTable="columnName" msprop:Generator_ColumnPropNameInRow="Name" msprop:Generator_ColumnPropNameInTable="NameColumn" msprop:Generator_UserColumnName="Name" type="xs:string" minOccurs="0" />
<xs:element name="Price" msprop:Generator_ColumnVarNameInTable="columnPrice" msprop:Generator_ColumnPropNameInRow="Price" msprop:Generator_ColumnPropNameInTable="PriceColumn" msprop:Generator_UserColumnName="Price" type="xs:double" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Order" msprop:Generator_TableClassName="OrderDataTable" msprop:Generator_TableVarName="tableOrder" msprop:Generator_TablePropName="Order" msprop:Generator_RowDeletingName="OrderRowDeleting" msprop:Generator_RowChangingName="OrderRowChanging" msprop:Generator_RowEvHandlerName="OrderRowChangeEventHandler" msprop:Generator_RowDeletedName="OrderRowDeleted" msprop:Generator_UserTableName="Order" msprop:Generator_RowChangedName="OrderRowChanged" msprop:Generator_RowEvArgName="OrderRowChangeEvent" msprop:Generator_RowClassName="OrderRow">
<xs:complexType>
<xs:sequence>
<xs:element name="ProductId" msprop:Generator_ColumnVarNameInTable="columnProductId" msprop:Generator_ColumnPropNameInRow="ProductId" msprop:Generator_ColumnPropNameInTable="ProductIdColumn" msprop:Generator_UserColumnName="ProductId" type="xs:int" />
<xs:element name="Qty" msprop:Generator_ColumnVarNameInTable="columnQty" msprop:Generator_ColumnPropNameInRow="Qty" msprop:Generator_ColumnPropNameInTable="QtyColumn" msprop:Generator_UserColumnName="Qty" type="xs:int" minOccurs="0" />
<xs:element name="UnitPrice" msprop:Generator_ColumnVarNameInTable="columnUnitPrice" msprop:Generator_ColumnPropNameInRow="UnitPrice" msprop:Generator_ColumnPropNameInTable="UnitPriceColumn" msprop:Generator_UserColumnName="UnitPrice" type="xs:double" minOccurs="0" />
<xs:element name="Total" msdata:ReadOnly="true" msdata:Expression="[Qty]*[UnitPrice]" msprop:Generator_ColumnVarNameInTable="columnTotal" msprop:Generator_ColumnPropNameInRow="Total" msprop:Generator_ColumnPropNameInTable="TotalColumn" msprop:Generator_UserColumnName="Total" type="xs:double" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
<xs:unique name="Constraint1" msdata:PrimaryKey="true">
<xs:selector xpath=".//mstns:Products" />
<xs:field xpath="mstns:Id" />
</xs:unique>
<xs:unique name="Order_Constraint1" msdata:ConstraintName="Constraint1" msdata:PrimaryKey="true">
<xs:selector xpath=".//mstns:Order" />
<xs:field xpath="mstns:ProductId" />
</xs:unique>
</xs:element>
</xs:schema>
Dim prod = _prodDataSet.Products.FindById(CInt(_prodIdNumericUpDown.Value))
If prod Is Nothing Then
MessageBox.Show("Not a product id")
Return
End If
'lookup the product in the order
Dim orderedProduct = _prodDataSet.Order.FindByProductId(prod.Id)
If orderedProduct Is Nothing Then
_prodDataSet.Order.AddOrderRow(prod.Id, 1, prod.Price)
Else
orderedProduct.Qty += 1
End If
'put it after InitializeComponent()
_prodDataSet.Products.AddProductsRow(1, "apples", 1.23)
_prodDataSet.Products.AddProductsRow(2, "oranges", 2.34)
_prodDataSet.Products.AddProductsRow(3, "pears", 3.45)
_prodDataSet
看起来像这样。 选择一个产品,单击添加,第一次单击它会将产品添加到订单中。 第二次单击它会增加现有项目的数量 - 如果您使用数据集/数据表,大约需要 5 行代码(恕我直言,这是应该完成的一种方式):
现在你所要做的就是把事情联系起来,这样你的数据库数据就会被输入到数据表中,而不是数据网格中。 这很容易 - 在设计器中打开该 DataSet,右键单击表面并选择 Add TableAdapter。 Go 通过向导将数据集连接到您的 mysql db。 (您需要为 Visual Studio 安装 MySQL以使您的生活更轻松)
我创建了一个包含所有项目属性的 class。 拥有参数化构造函数 ( Sub New
) 可确保 Item 拥有其所有数据。 ComboBox 在添加项目时将在我们的 class 上调用ToString
。 ToString 的覆盖告诉 ComboBox 要显示什么。
Public Class Item
Public Property ProductCode As Integer
Public Property BarCode As String
Public Property Name As String
Public Property Price As Decimal
Public Property ItemProductType As String
Public Sub New(ProCode As Integer, BCode As String, Nm As String, Pr As Decimal, Type As String)
ProductCode = ProCode
BarCode = BCode
Name = Nm
Price = Pr
ItemProductType = Type
End Sub
Public Overrides Function ToString() As String
Return Name
End Function
End Class
Imports MySql.Data.MySqlClient
Form.Load 只需调用 2 个方法。
Public Class PointOfSale
Private Sub PointOfSale_Load(sender As Object, e As EventArgs) Handles MyBase.Load
FillComboBox()
BindGrid()
End Sub
我将Items
列表设置为 Form 级别的变量,以防您在其他方法中需要它。 如果事实证明你没有,你可以在FillComboBox
方法中移动它
Private Items As New List(Of Item)
此方法使用GetComboData
检索DataTable
。 为 DataTable 中的每一行创建一个New Item
。 然后将该Item
添加到项目列表中。 ComboBox 使用该列表作为其DataSource
。 重要的是,整个Item
object 存储在 ComboBox 中。 在任何时候,我们都可以将SelectedItem
转换回其基础类型 ( Item
) 并访问其所有属性。 ComboBox 在Item
上调用ToString
并显示我们在 Item class 中编码的Name
属性。
Private Sub FillComboBox()
Dim dt = GetComboData()
For Each row As DataRow In dt.Rows
Dim It As New Item(CInt(row(0)), row(1).ToString, row(2).ToString, CDec(row(3)), row(4).ToString)
Items.Add(It)
Next
ComboBox1.DataSource = Items
End Sub
此数据访问方法从 item 表和 products 表中获取数据。 productCode
是 Items 表中的外键。
Private Function GetComboData() As DataTable
Dim dt As New DataTable
Dim sql = "Select
items.productCode,
items.barCode,
items.`name`,
items.price,
products.productName
From items
Inner Join products
on items.productCode = products.productCode;"
Using cn As New MySqlConnection(My.Settings.POSConnection),
cmd As New MySqlCommand(sql, cn)
cn.Open()
dt.Load(cmd.ExecuteReader)
End Using
Return dt
End Function
转到从 Form.Load 调用的第二个方法。 我们创建一个最初没有数据的DataTable
。 它确实有具有数据类型的列。 最后一列是计算列,当数据添加到DataTable
时将显示计算结果
Private dat As New DataTable
Private Sub BindGrid()
With dat.Columns
.Add("Product Code", GetType(Integer))
.Add("Product Type", GetType(String))
.Add("Bar Code", GetType(String))
.Add("Product Name", GetType(String))
.Add("Price", GetType(Decimal))
.Add("Quantity", GetType(Integer))
.Add("Total", GetType(Decimal), "Price * Quantity")
End With
DataGridView1.DataSource = dat
End Sub
将项目添加到订单涉及将数据添加到DataTable
。 它将显示在网格中,因为网格将此DataTable
用作DataSource
。 首先,我们将组合中的选定项目转换回其基础类型( Item
类)。 现在我们可以访问所有属性来填充DataTable
。 Quantity
检索的是 NumericUpDown 而不是文本框,因此我们不必检查它是否是有效数字。 总计是通过遍历 DataTable 中获取计算值的行来计算的。
Private Sub btnAddToOrder_Click(sender As Object, e As EventArgs) Handles btnAddToOrder.Click
Dim it = DirectCast(ComboBox1.SelectedItem, Item)
dat.Rows.Add({it.ProductCode, it.ItemProductType, it.BarCode, it.Name, it.Price, NumericUpDown1.Value})
Dim Total As Decimal
For Each row As DataRow In dat.Rows
Total += CDec(row("Total"))
Next
txtGrandTotal.Text = Total.ToString
End Sub
结束 Class
这可能是也可能不是您正在寻找的东西,但它可能会让您了解另一种方法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.