thongkorn โพสต์ 2017-10-23 10:04:24

[VB.NET] การนำ ComboBox Control ไปใส่ไว้ในตารางกริด DataGridView แบบ Run Time

http://www.g2gnet.com/webboard/images/vbnet/DataGridComboNet.png
จากตอนที่แล้วแอดมินได้นำเสนอ การนำเอา ComboBox Control ไปใส่ไว้ในตารางกริด MSFlexGrid สำหรับ Visual Basic 6 ในตอนนี้ก็จะขยับมาใช้ VB.NET โดยแบ่งวิธีคิดออกเป็น 3 วิธี ซึ่งแต่ละวิธีจะมีทั้งความเหมือนและความแตกต่างผสมกันไป แอดมินอยากให้ลองศึกษาและสังเกตกันให้ดีๆ เพราะสิ่งที่แอดมินนำมาเล่าสู่กันฟังนี้มันเป็นพื้นฐาน ที่จะนำทางไปสู่การแก้ปัญหาในการเขียนโปรแกรมในลำดับต่อไป ...

3 วิธีคิด แบ่งออกได้ดังต่อไปนี้
- คิดแบบ VB6
- คิดแบบ VB6 แต่ใช้ความสามารถของ VB.NET ในการสร้าง ComboBox แบบ @Run Time
- คิดแบบ Visual Basic .NET ฉบับเต็ม

สำหรับวิธีแรก คงไม่ต้องอธิบายอะไรมากมายนัก ก็คือนำเอา ComboBox มาแปะลงบนฟอร์มก่อน จากนั้นก็อาศัยหลักการเลื่อนตำแหน่ง ComboBox ไปปิดทับในแต่ละเซลล์ที่ต้องการ (ใช้หลักที่ 3 หรือ Index = 2 ตามเดิม)
โค้ดวิธีการแรก
Public Class frmDGVCBV1

    Private Sub frmDGVCBV1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
      '//
      With DataGridView1
            .AllowUserToAddRows = False
            .AllowUserToDeleteRows = False
            .SelectionMode = DataGridViewSelectionMode.CellSelect
            .AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill
            .AutoResizeColumns()
            .MultiSelect = False
            .ColumnCount = 3
            .Columns(0).Name = "Column 1"
            .Columns(1).Name = "Column 2"
            .Columns(2).Name = "Column 3"
            '// ป้องกันการเข้าไปแก้ไขในเซลล์โดยตรง
            .Columns(2).ReadOnly = True
      End With

      Dim row As String() = New String() {"1", "Product 1", "M100"}
      DataGridView1.Rows.Add(row)
      row = New String() {"2", "Product 2", "M100"}
      DataGridView1.Rows.Add(row)
      row = New String() {"3", "Product 3", "M150"}
      DataGridView1.Rows.Add(row)
      row = New String() {"4", "Product 4", "M16"}
      DataGridView1.Rows.Add(row)
      '//
      With ComboBox1
            .DropDownStyle = 2
            '// Load the ComboBox's list.
            .Items.Add("M100")
            .Items.Add("M150")
            .Items.Add("M16")
            ' Hidden Control
            .Visible = False
      End With
    End Sub

    ' / -------------------------------------------------------------------------------------
    ' / เกิดเหตุการณ์การคลิ๊กเซลล์ แถวใดๆแต่เป็นหลักที่ 3 (Index = 2)
    Private Sub DataGridView1_CellClick(sender As Object, e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DataGridView1.CellClick
      If e.RowIndex < 0 Then Exit Sub

      Select Case e.ColumnIndex
            '// เราไม่ต้องการหลัก 0 กับหลัก 1 ดังนั้นต้องปิดการแสดงผลของ ComboBox เอาไว้
            Case 0 To 1 : ComboBox1.Visible = False

                '// โฟกัสมาที่หลักที่ 3 (Index = 2) ที่เราต้องการเท่านั้น
            Case 2
                '// เปิดให้มองเห็น ComboBox
                ComboBox1.Visible = True
                '// เพิ่ม ComboBox เข้ามาในตารางกริด
                DataGridView1.Controls.Add(ComboBox1)
                '// นำค่าจาก DataGrid มาเทียบค่าใน ComboBox เพื่อให้แสดงผลค่าที่เท่ากัน
                ComboBox1.Text = DataGridView1.Rows(e.RowIndex).Cells(e.ColumnIndex).Value
                '// พื้นที่แสดงผลในเซลล์.
                Dim oRectangle = DataGridView1.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, True)
                ' หาค่าระยะ X, Y เพื่อกำหนดพิกัด (Coordinate) ให้กับ ComboBox
                ComboBox1.Size = New Size(oRectangle.Width, oRectangle.Height)
                '// กำหนดตำแหน่งของ ComboBox ไปทับเซลล์
                ComboBox1.Location = New Point(oRectangle.X, oRectangle.Y)
      End Select
    End Sub

    ' / -------------------------------------------------------------------------------------
    ' / หากเกิดการเลือกค่าใน ComboBox ก็ให้คัดลอกค่านี้ไปยังเซลล์ใน DataGridView
    Private Sub ComboBox1_TextChanged(sender As Object, e As System.EventArgs) Handles ComboBox1.TextChanged
      '// นำค่าจาก ComboBox ไปใส่ไว้ในเซลล์ของ DataGridView
      DataGridView1.CurrentCell.Value = ComboBox1.Text
    End Sub

    Private Sub frmDGVCBV1_Resize(sender As Object, e As System.EventArgs) Handles Me.Resize
      ComboBox1.Visible = False
    End Sub

    Private Sub ComboBox1_SelectedIndexChanged(sender As System.Object, e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged
      '// นำค่าจาก ComboBox ไปใส่ไว้ในเซลล์ของ DataGridView
      DataGridView1.CurrentCell.Value = ComboBox1.Text
    End Sub

    Private Sub frmDGVCBV1_FormClosed(sender As Object, e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
      Me.Dispose()
    End Sub

End Class
วิธีการที่สอง ก็จะใช้เหมือนวิธีการแรก แต่เปลี่ยนใหม่โดยให้สร้าง ComboBox Control ขึ้นมาในขณะ @Run Time แทน
'// ประกาศตัวแปร Object ของ ComboBox
    Dim cb As New ComboBoxประกาศตัวแปร ComboBox
      '// Declare columns type.
      Dim Column1 As New DataGridViewTextBoxColumn()
      Dim Column2 As New DataGridViewTextBoxColumn()
      Dim Column3 As New DataGridViewTextBoxColumn()
      '// Add new Columns
      DataGridView1.Columns.AddRange(New DataGridViewColumn() { _
                Column1, Column2, Column3 _
                })
      With DataGridView1
            .Columns(0).Name = "Column 1"
            .Columns(1).Name = "Column 2"
            .Columns(2).Name = "Column 3"
            '// ป้องกันการเข้าไปแก้ไขในเซลล์โดยตรง
            .Columns(2).ReadOnly = True
      End With
      '//
      With cb
            .DropDownStyle = 2
            '// Load the ComboBox's list.
            .Items.Add("M100")
            .Items.Add("M150")
            .Items.Add("M16")
            '// Hidden Control
            .Visible = False
      End Withให้สังเกตดูว่าในหลักที่ 3 (Index = 2) แอดมินยังกำหนดช่องเซลล์ DataGridViewTextBoxColumn คือยังคงเป็นแบบ TextBox ตามเดิม

    ' / -------------------------------------------------------------------------------------
    ' / เกิดเหตุการณ์การคลิ๊กเซลล์ แถวใดๆแต่เป็นหลักที่ 3 (Index = 2)
    Private Sub DataGridView1_CellClick(sender As Object, e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DataGridView1.CellClick
      If e.RowIndex < 0 Then Exit Sub

      Select Case e.ColumnIndex
            '// เราไม่ต้องการหลัก 0 กับหลัก 1 ดังนั้นต้องปิดการแสดงผลของ ComboBox เอาไว้
            Case 0 To 1 : cb.Visible = False

                '// โฟกัสมาที่หลักที่ 3 (Index = 2) ที่เราต้องการเท่านั้น
            Case 2
                '// เปิดให้มองเห็น ComboBox
                cb.Visible = True
                '// Adding ComboBox control into DataGridView   
                DataGridView1.Controls.Add(cb)
                '// นำค่าจาก DataGrid มาเทียบค่าใน ComboBox เพื่อให้แสดงผลค่าที่เท่ากัน
                cb.Text = DataGridView1.CurrentCell.Value
                '// พื้นที่แสดงผลในเซลล์.
                Dim oRectangle = DataGridView1.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, True)
                ' หาค่าระยะ X, Y เพื่อกำหนดพิกัด (Coordinate) ให้กับ ComboBox
                cb.Size = New Size(oRectangle.Width, oRectangle.Height)
                '// Setting Location
                cb.Location = New Point(oRectangle.X, oRectangle.Y)

                '// การสร้างเหตุการณ์ (Event) เมื่อเกิดการเลือกไอเทมใน ComboBox ก็จะส่งผลให้กับเซลล์ในตารางกริด
                AddHandler cb.TextChanged, AddressOf cb_TextChanged
      End Select
    End Sub

    ' / -------------------------------------------------------------------------------------
    ' / หากเกิดการเลือกค่าใน ComboBox ก็ให้คัดลอกค่านี้ไปยังเซลล์ใน DataGridView
    Private Sub cb_TextChanged(sender As Object, e As System.EventArgs)
      cb.Visible = False
      '// นำค่าจาก ComboBox ไปใส่ไว้ในเซลล์ของ DataGridView
      If DataGridView1.CurrentCell.ColumnIndex = 2 AndAlso cb.Text <> "" Then DataGridView1.CurrentCell.Value = cb.Text
    End Subนอกเหนือไปจากการคำนวณหาตำแหน่งที่ ComboBox จะต้องเคลื่อนย้ายไปปิดทับเซลล์แล้ว เราจะต้องสร้างเหตุการณ์ (Event) เมื่อเกิดการเลือกค่าไอเทมใน ComboBox เพิ่มขึ้นมาอีก (AddHandler cb.TextChanged, AddressOf cb_TextChanged) ในส่วนนี้เองที่ VB.NET ได้เพิ่มขีดความสามารถขึ้นมาสูงกว่า VB6

โค้ดวิธีการที่สอง
Public Class frmDGVCBV2
    '// ประกาศตัวแปร Object ของ ComboBox
    Dim cb As New ComboBox

    Private Sub frmDGVCBV2_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
      '//
      With DataGridView1
            .AllowUserToAddRows = False
            .AllowUserToDeleteRows = False
            .SelectionMode = DataGridViewSelectionMode.CellSelect
            .AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill
            .AutoResizeColumns()
            .MultiSelect = False
      End With
      '// Declare columns type.
      Dim Column1 As New DataGridViewTextBoxColumn()
      Dim Column2 As New DataGridViewTextBoxColumn()
      Dim Column3 As New DataGridViewTextBoxColumn()
      '// Add new Columns
      DataGridView1.Columns.AddRange(New DataGridViewColumn() { _
                Column1, Column2, Column3 _
                })
      With DataGridView1
            .Columns(0).Name = "Column 1"
            .Columns(1).Name = "Column 2"
            .Columns(2).Name = "Column 3"
            '// ป้องกันการเข้าไปแก้ไขในเซลล์โดยตรง
            .Columns(2).ReadOnly = True
      End With
      '//
      With cb
            .DropDownStyle = 2
            '// Load the ComboBox's list.
            .Items.Add("M100")
            .Items.Add("M150")
            .Items.Add("M16")
            '// Hidden Control
            .Visible = False
      End With
      '//
      Dim row As String() = New String() {"1", "Product 1", "M100"}
      DataGridView1.Rows.Add(row)
      row = New String() {"2", "Product 2", "M100"}
      DataGridView1.Rows.Add(row)
      row = New String() {"3", "Product 3", "M150"}
      DataGridView1.Rows.Add(row)
      row = New String() {"4", "Product 4", "M16"}
      DataGridView1.Rows.Add(row)
    End Sub

    ' / -------------------------------------------------------------------------------------
    ' / เกิดเหตุการณ์การคลิ๊กเซลล์ แถวใดๆแต่เป็นหลักที่ 3 (Index = 2)
    Private Sub DataGridView1_CellClick(sender As Object, e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DataGridView1.CellClick
      If e.RowIndex < 0 Then Exit Sub

      Select Case e.ColumnIndex
            '// เราไม่ต้องการหลัก 0 กับหลัก 1 ดังนั้นต้องปิดการแสดงผลของ ComboBox เอาไว้
            Case 0 To 1 : cb.Visible = False

                '// โฟกัสมาที่หลักที่ 3 (Index = 2) ที่เราต้องการเท่านั้น
            Case 2
                '// เปิดให้มองเห็น ComboBox
                cb.Visible = True
                '// Adding ComboBox control into DataGridView   
                DataGridView1.Controls.Add(cb)
                '// นำค่าจาก DataGrid มาเทียบค่าใน ComboBox เพื่อให้แสดงผลค่าที่เท่ากัน
                cb.Text = DataGridView1.CurrentCell.Value
                '// พื้นที่แสดงผลในเซลล์.
                Dim oRectangle = DataGridView1.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, True)
                ' หาค่าระยะ X, Y เพื่อกำหนดพิกัด (Coordinate) ให้กับ ComboBox
                cb.Size = New Size(oRectangle.Width, oRectangle.Height)
                '// Setting Location
                cb.Location = New Point(oRectangle.X, oRectangle.Y)

                '// การสร้างเหตุการณ์ (Event) เมื่อเกิดการเลือกไอเทมใน ComboBox ก็จะส่งผลให้กับเซลล์ในตารางกริด
                AddHandler cb.TextChanged, AddressOf cb_TextChanged
      End Select
    End Sub

    ' / -------------------------------------------------------------------------------------
    ' / หากเกิดการเลือกค่าใน ComboBox ก็ให้คัดลอกค่านี้ไปยังเซลล์ใน DataGridView
    Private Sub cb_TextChanged(sender As Object, e As System.EventArgs)
      cb.Visible = False
      '// นำค่าจาก ComboBox ไปใส่ไว้ในเซลล์ของ DataGridView
      If DataGridView1.CurrentCell.ColumnIndex = 2 AndAlso cb.Text <> "" Then DataGridView1.CurrentCell.Value = cb.Text
    End Sub

    ' / -------------------------------------------------------------------------------------
    ' / หากเกิดการเลือกค่าใน ComboBox ก็ให้คัดลอกค่านี้ไปยังเซลล์ใน DataGridView
    Private Sub DataGridView1_CellLeave(sender As Object, e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DataGridView1.CellLeave
      cb.Visible = False
      If DataGridView1.CurrentCell.ColumnIndex = 2 AndAlso cb.Text <> "" Then DataGridView1.CurrentCell.Value = cb.Text
    End Sub

    Private Sub frmDGVCBV2_Resize(sender As Object, e As System.EventArgs) Handles Me.Resize
      cb.Visible = False
    End Sub

    Private Sub frmDGVCBV2_FormClosed(sender As Object, e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
      Me.Dispose()
    End Sub

End Class
สำหรับวิธีการที่สาม เราๆท่านๆก็คงจะพบเห็นข้อมูลได้ทั่วๆไปตามเว็บไซต์ต่างๆนั่นเอง โดยอาศัยขีดความสามารถที่มีอยู่ในตัวของ VB.NET ในการเพิ่ม Control ในตัวของ DataGridView ...
      '// เพิ่ม ComboBox
      Dim cmb As New DataGridViewComboBoxColumn()
      With cmb
            .HeaderText = "ComboBox"
            .Items.Add("M100")
            .Items.Add("M150")
            .Items.Add("M16")
      End With
      DataGridView1.Columns.Add(cmb)ก็เพราะ DataGridView มันมีกลวิธี (Method) ในการนำเอา ComboBox มาใส่ไว้ในเซลล์ของตัวมันเองได้นั่นเอง
โค้ดวิธีการที่สาม
Public Class frmDGVCBV3

    Private Sub frmDGVCBV3_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
      '//
      With DataGridView1
            .AllowUserToAddRows = False
            .AllowUserToDeleteRows = False
            .SelectionMode = DataGridViewSelectionMode.CellSelect
            .AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill
            .AutoResizeColumns()
            .MultiSelect = False
      End With
      '// Declare columns type.
      Dim Column1 As New DataGridViewTextBoxColumn()
      Dim Column2 As New DataGridViewTextBoxColumn()
      '// Add new Columns
      DataGridView1.Columns.AddRange(New DataGridViewColumn() { _
                Column1, Column2 _
                })
      With DataGridView1
            .Columns(0).Name = "Column 1"
            .Columns(1).Name = "Column 2"
      End With
      '// เพิ่ม ComboBox
      Dim cmb As New DataGridViewComboBoxColumn()
      With cmb
            .HeaderText = "ComboBox"
            .Items.Add("M100")
            .Items.Add("M150")
            .Items.Add("M16")
      End With
      DataGridView1.Columns.Add(cmb)
      '//
      Dim row As String() = New String() {"1", "Product 1", "M100"}
      DataGridView1.Rows.Add(row)
      row = New String() {"2", "Product 2", "M100"}
      DataGridView1.Rows.Add(row)
      row = New String() {"3", "Product 3", "M150"}
      DataGridView1.Rows.Add(row)
      row = New String() {"4", "Product 4", "M16"}
      DataGridView1.Rows.Add(row)
      '//
    End Sub

    Private Sub frmDGVCBV3_FormClosed(sender As Object, e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
      Me.Dispose()
    End Sub

End Class
Conclusion: หลายๆคนอาจจะงงและสงสัยว่า ทำไมแอดมินต้องมาใช้วิธีการอะไรให้ยุ่งยาก ก็เล่นแบบวิธีการที่ 3 ไปเลยซ่ะก็สิ้นเรื่อง ... ลองคิดเล่นๆดูก่อนว่าหากเราต้องการเพิ่ม DateTimePicker (หรือ Control ตัวอื่นๆ) เข้าไปในเซลล์ของตารางกริดแทน ComboBox ท่านจะทำอย่างไร???
ดาวนโหลดโค้ดต้นฉบับ VB.NET (2010) ได้ที่นี่

komenservice โพสต์ 2020-7-14 11:26:30

มีตัวอย่างแบบทำเป็นChedkbox ไหมครับ

thongkorn โพสต์ 2020-7-14 18:55:17

komenservice ตอบกลับเมื่อ 2020-7-14 11:26
มีตัวอย่างแบบทำเป็นChedkbox ไหมครับ

      Dim chk As New DataGridViewCheckBoxColumn()
      chk.HeaderText = "Check Box"
      DataGridView1.Columns.Add(chk)
      '//
      Dim row As String() = New String() {"1", "Product 1", "M100", True}
      DataGridView1.Rows.Add(row)
      row = New String() {"2", "Product 2", "M100", False}
      DataGridView1.Rows.Add(row)
      row = New String() {"3", "Product 3", "M150", False}
      DataGridView1.Rows.Add(row)
      row = New String() {"4", "Product 4", "M16", True}
      DataGridView1.Rows.Add(row)

g2gsoftuser โพสต์ 2022-10-25 14:52:48

ขอบคุณครับ
หน้า: [1]
ดูในรูปแบบกติ: [VB.NET] การนำ ComboBox Control ไปใส่ไว้ในตารางกริด DataGridView แบบ Run Time