thongkorn โพสต์ 2017-11-14 10:03:19

[VB.NET] แจกโค้ดการกำหนดปุ่มคำสั่งแบบ RunTime และทดสอบข้อมูลด้วย DataTable โปรเจคทองก้อนเบอเกอร์แดนซ์

http://www.g2gnet.com/webboard/images/vbnet/BurgerDataTable.png
มาว่ากันอย่างต่อเนื่องไปเลยครับ จะได้รู้ว่า การเขียนโปรแกรมน่ะมันไม่ยากหรอก แต่การออกแบบจัดเรียงลำดับขั้นตอน ซอกซอนแยกย่อยออกเป็นส่วนๆ เพื่อหาคำตอบนี่ซิ คือความหมายของการเขียนโปรแกรมอย่างแท้จริง จากภาคแรกอินโทร แจกฟรีโค้ดต้นฉบับ โปรแกรมต้นแบบร้านทองก้อนเบอเกอร์แดนซ์เราจะเห็นได้ว่าการกำหนดปุ่มคำสั่ง (Button Control) มันเป็นแบบ Static ทั้งการโหลดภาพและกำหนดข้อมูลต่างๆในแบบ Design Time มาตอนนี้ก็จะยังเป็น Design Time อยู่เหมือนเดิมนั่นแหละครับ แต่จะเริ่มเป็น Dynamic มากขึ้นกว่าเดิม ด้วยการกำหนดค่าต่างๆของปุ่มคำสั่งในแบบ Run Time และ จะใช้ DataTable เพื่อจำลองข้อมูล ก่อนจะนำไปออกแบบในงานจริงอีกที นอกจากนี้ยังเพิ่มการตรวจสอบการซื้อสินค้ารายการเดียวกัน แต่เพิ่มจำนวน (Quantity) เข้าไป แทนการเพิ่มแถว (Add Row) ... ที่ว่ามานี้ ยังไม่ได้ใช้งานฐานข้อมูลอีกแล้วครับท่าน ...

มาดูข้อมูลตุ๊กตาที่ถูกสร้างไว้ใน DataTable
    ' / ---------------------------------------------------------------
    '// ตัวอย่างเป็นตารางข้อมูล (Table)
    Function GetTable() As DataTable
      DT = New DataTable
      '/ Add columns.
      DT.Columns.Add("PK", GetType(Integer))
      DT.Columns.Add("Description", GetType(String))
      DT.Columns.Add("UnitPrice", GetType(Double))
      DT.Columns.Add("Quantity", GetType(Integer))
      DT.Columns.Add("Picture", GetType(String))
      '// Add rows.
      '// PK, Desciption, UnitPrice, Quantity (เผื่อเอาไว้สำหรับหากมีการนับสต็อก), Picture
      DT.Rows.Add(1, "Classic Checken", "45.00", 1, "BurgerChicken.png")
      DT.Rows.Add(2, "Mexicana", "85.00", 1, "BurgerMexicana.png")
      DT.Rows.Add(3, "Lemon Shrimp", "110.00", 1, "BurgerLemonShrimp.png")
      DT.Rows.Add(4, "Bacon", "90.00", 1, "BurgerBacon.png")
      DT.Rows.Add(5, "Spicy Shrimp", "120.00", 1, "BurgerSpicyShrimp.png")
      DT.Rows.Add(6, "Tex Supreme", "80.00", 1, "BurgerTexSupreme.png")
      DT.Rows.Add(7, "Fish", "100.00", 1, "BurgerFish.png")
      '//
      Return DT
    End Functionตัวอย่างที่ลองออกแบบกับ DataTable ... ไม่ว่างานไหนงานนั้น แอดมินชอบหลบซ่อนตัว PK หรือย่อมาจาก Primary Key ซึ่งถือว่าเป็นกุญแจหลักเสมอ

การกำหนดค่าคุณสมบัติให้กับปุ่มคำสั่งแบบ Run Time
      '// Acquire the DataTable instance.
      DT = GetTable()
      Dim row As DataRow
      Dim img As String
      '// ใส่ปุ่มทั้งหมดในอาร์เรย์หรือคอลเล็กชันอื่นๆ เช่น List (Of Button)
      Dim myButtons = {btnBurger1, btnBurger2, btnBurger3, btnBurger4, btnBurger5, btnBurger6, btnBurger7}
      Dim Rec As Integer = 0
      '/ โหลดรายละเอียดของปุ่มคำสั่ง @RunTime
      For Each btn In myButtons
            row = DT.Rows(Rec)
            With btn
                .Tag = row("PK")
                .Text = row("Description")
                img = strPathImage & row("Picture")
                .BackgroundImage = New System.Drawing.Bitmap(img)
            End With
            Rec += 1
      Nextโปรดสังเกตเล็กๆว่า แอดมินนำค่า PK ไปซ่อนไว้ในคุณสมบัติ Tag ของ Button เพราะเราจะใช้ค่านี้ทำ Query รายละเอียดของสินค้าชิ้นนี้ เช่น ราคา จำนวนในสต็อก

เมื่อเกิดการกดปุ่มคำสั่ง
    Private Sub btnBurger1_Click(sender As System.Object, e As System.EventArgs) Handles btnBurger1.Click
      '// หากนำไปใช้งานจริง ข้อมูลของตัวสินค้าจะถูกเรียกมาจากตารางข้อมูล
      '// เมื่อคลิ๊กกดปุ่ม จะค้นหาข้อมูลด้วยค่า PK (Primary Key) ที่ถูกซ่อนเอาไว้ในคุณสมบัติ TAG ของ Button
      Dim oRow() As DataRow = DT.Select("PK = " & btnBurger1.Tag)
      '//
      Call AddRow(oRow(0)("PK"), btnBurger1.Text, CDbl(oRow(0)("UnitPrice")))
    End Subการค้นหา PK จาก DataRow ด้วยค่า PK ที่ถูกซ่อนไว้ใน Tag ... แต่ทว่าหากเรามี 200 ปุ่มคำสั่ง เราก็ต้องสร้างเหตุการณ์แบบนี้ขึ้นมาใหม่หมดทั้ง 200 รายการ ซึ่งแบบมันก็คงไม่ไหวหรอกครับ มันมีวิธีแก้ปัญหาที่ดีกว่านี้ ซึ่งผมมองข้ามช็อตไปแล้ว ... คุณล่ะ???

การเพิ่มรายการและจำนวนสินค้า
    ' / ---------------------------------------------------------------
    ' / เพิ่มรายการแถวใหม่ (UnBound Data)
    Private Sub AddRow(ByVal PK As Integer, ByVal Description As String, ByVal UnitPrice As Double)
      Dim blnExist As Boolean = False
      For Rec As Integer = 0 To dgvData.RowCount - 1
            ' / หากพบ Primary Key ในหลัก 0 มาตรงกันกับค่าในแถวของตารางกริด
            If dgvData.Rows(Rec).Cells(0).Value = PK Then
                ' / ให้บวกจำนวนที่เลือกเพิ่มขึ้นอีก 1 (Quantity = Quantity + 1)
                dgvData.Rows(Rec).Cells(3).Value = dgvData.Rows(Rec).Cells(3).Value + 1
                blnExist = True
                '// เมื่อพบแล้วก็ให้เด้งออกจาก For ไปเลยทันที จะได้ไม่ต้องเสียเวลาวนรอบใหม่
                Exit For
            End If
      Next
      '// หากไม่พบข้อมูลที่อยู่ในตารางกริด ก็ให้เพิ่มแถวใหม่
      If Not blnExist Then
            Dim row As String() = New String() {PK, Description, Format(CDbl(UnitPrice), "#,##0.00"), 1}
            dgvData.Rows.Add(row)
      End If
      '// โฟกัสไปที่ DataGridView แล้วย้ายไปแถวล่าสุด
      dgvData.Focus()
      SendKeys.Send("^{END}")
    End Subเกิดจากการวนรอบในแถวทั้งหมดของตารางกริด โดยเอาค่า PK ที่อยู่ใน Tag ของปุ่มคำสั่ง ไปเปรียบเทียบกับหลักแรก (Index = 0) ที่เราซ่อนมันเอาไว้ ในแต่ละแถวของตารางกริด ซึ่งมันก็คือค่า PK เช่นเดียวกัน หากมีค่าตรงกันก็ให้เพิ่ม 1 แล้วออกจาก For Loop แต่หากหาไม่พบก็แสดงว่าเป็นข้อมูลใหม่ ก็ให้เพิ่มแถวเข้าไป ... หลักการคิดก็มีแค่นี้เอง หมูน้อยร้องเหมียวๆเลยมั้ย

การลบรายการสินค้า
    ' / ---------------------------------------------------------------
    Private Sub btnRemove_Click(sender As System.Object, e As System.EventArgs) Handles btnRemove.Click
      If dgvData.RowCount <= 0 Then Exit Sub
      dgvData.Focus()
      '// ใช้หลัก PK (ที่ถูกซ่อน) เป็นกุญแจหลักในการอ้างอิง
      Dim PK As Integer = dgvData.CurrentRow.Cells(0).Value
      '// หาแถวที่เลือก
      Dim Rec As Integer = dgvData.CurrentRow.Index
      '/ หากแถวที่เลือกมีจำนวนเท่ากับ 1 ก็ให้ลบแถวออกไป
      If dgvData.Rows(Rec).Cells(3).Value = 1 Then
            dgvData.Rows.Remove(dgvData.CurrentRow)
            '/ หากแถวที่เลือกมีจำนวนมากกว่า 1
      Else
            ' / ให้ลบจำนวนลง 1 (Quantity = Quantity - 1)
            dgvData.Rows(Rec).Cells(3).Value = dgvData.Rows(Rec).Cells(3).Value - 1
      End If
    End Subก็โฟกัสไปแถวที่เลือก (CurrentRow) จากนั้นไปดูที่หลัก 4 (Index = 3) ตรวจสอบว่ามีค่ามากกว่า 1 หรือไม่ หากใช่ให้ลบออก 1 แต่หากมีค่าเท่ากับ 1 ก็ลบแถวนั้นทิ้งไป ... หลักการคิดก็มีแค่นี้เอง แมวเหมียวร้องอู๊ดๆอีกแล้วครับท่าน 5555+

Conclusion: มาถึง ณ จุดนี้ (ได้ยังไง) ก็ยังไม่มีการเชื่อมต่อเข้ากับตารางข้อมูลแต่อย่างใด แต่เป็นการเขียนโปรแกรมขึ้นมาเพื่อทดสอบ โดยมองมายังคำตอบ คำตอบที่ว่าก็คือ เรามีฟิลด์ข้อมูลอะไรบ้างที่ต้องใช้ต้องเก็บ จากนั้นก็กลับไปตั้งหลักเพื่อเอาคำตอบมาช่วยในการออกแบบ วิธีการนี้แอดมินเรียกมันว่า Backward Algorithm นั่นเอง
ดาวน์โหลดโค้ดต้นฉบับ VB.NET (2010) แบบเต็มได้ที่

Taplet โพสต์ 2017-11-14 13:47:09

ขอบพระคุณครับ ...

MrDen โพสต์ 2017-11-16 13:40:31

Thank you very much ครับผม :)

aek51 โพสต์ 2017-12-4 22:55:40

ขอบคุณมากครับ   :loveliness:
หน้า: [1]
ดูในรูปแบบกติ: [VB.NET] แจกโค้ดการกำหนดปุ่มคำสั่งแบบ RunTime และทดสอบข้อมูลด้วย DataTable โปรเจคทองก้อนเบอเกอร์แดนซ์