繁体   English   中英

在 DataGridView 中的现有项目中添加数量的问题 - vb.net

[英]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

这是 output 图像

这是我的做法:

  • 做一个新项目
  • 将 Form1 重命名为 MainForm
  • 添加一个 DataSet 类型的文件,称为 ProdDataSet。 关闭它 id VS 打开它
  • 在文本编辑器中打开 ProdDataSet.xsd 并将其粘贴到整个内容的顶部:
<?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>
  • 保存。 在 Visual Studio 的设计器视图中重新打开它(双击它)并将表格排列在里面,再次保存(它会导致在设计器中保存时生成必要的代码)
  • 在窗体中添加一个 NumericUpDown 控件并将其命名为 _prodIdNumericUpDown
  • 向表单添加一个按钮,将其命名为 _addButton。 双击它并将此代码放入处理程序中:

        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)
    
  • 打开数据源 window(查看菜单,其他窗口)并将每个 Order 和 Products 节点拖到表单中以创建网格。 在表单底部的托盘中,确保将数据集重命名为_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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM