2014年2月26日 星期三

VB.Net 動態生成子控制(Button,TextBox)

引用來源:VB.Net 動態生成子控制(Button,TextBox)
--
 動態生成子控制不是問題,重點是怎麼把對應的函式自動加進去。

範例一 - 動態生成 TextBox

Public Class Form
    '  動態生成 TextBox

    Private Sub Form_Shown(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Shown

        Dim myTextBox As TextBox

        ' const declare
        Const x0 As Int32 = 20
        Const y0 As Int32 = 20
        Const w As Int32 = 100
        Const h As Int32 = 30
        Const hd As Int32 = 10
        Const cnt As Int32 = 4

        Dim i As Int32 = 0

        ' 動態生成 TextBox
        For i = 0 To cnt - 1
            myTextBox = New TextBox()
            myTextBox.Text = "button" & i
            myTextBox.Left = x0
            myTextBox.Top = y0 + i * (h + hd)
            myTextBox.Width = w
            myTextBox.Height = h
            Me.Controls.Add(myTextBox)
            AddHandler myTextBox.Click, AddressOf myTextBoxClick ' 交附給函式
        Next
    End Sub

    Private Sub myTextBoxClick(ByVal sender As Object, ByVal e As System.EventArgs)
        System.Windows.Forms.MessageBox.Show(CType(sender, TextBox).Text)
    End Sub
End Class

範例二 - 動態生成 Button (1)

初版的動態生成 Button 缺點不少,這裡是將 myButton 使用動態陣列,每個陣列名字都長得差不多,另外對應函式是用一個一個 map 起來的。原始碼如下

Public Class Form
    '  動態生成按扭
    Private myButton() As Button

    Private Sub Form_Shown(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Shown
        ' const declare
        Const x0 As Int32 = 20
        Const y0 As Int32 = 20
        Const w As Int32 = 100
        Const h As Int32 = 30
        Const hd As Int32 = 10
        Const cnt As Int32 = 4

        Dim i As Int32 = 0
        ReDim myButton(cnt)

        ' 動態生成 button
        For i = 0 To cnt - 1
            myButton(i) = New Button()
            myButton(i).Text = "button" & i
            myButton(i).Left = x0
            myButton(i).Top = y0 + i * (h + hd)
            myButton(i).Width = w
            myButton(i).Height = h
            Me.Controls.Add(myButton(i))
        Next

        ' 進行函式對應
        AddHandler myButton(0).Click, AddressOf Func0
        AddHandler myButton(1).Click, AddressOf Func1
        AddHandler myButton(2).Click, AddressOf Func2
        AddHandler myButton(3).Click, AddressOf Func3
    End Sub

    Sub Func0()
        MsgBox("func0")
    End Sub

    Sub Func1()
        MsgBox("func1")
    End Sub

    Sub Func2()
        MsgBox("func2")
    End Sub

    Sub Func3()
        MsgBox("func3")
    End Sub
End Class

範例三 - 動態生成 Button (2)

第二版動態生成按鈕改善了一點點,由於這幾顆按鈕做的事都一樣,所以便用委派方式給同一個函式執行,但實際上效果並不彰。

Public Class Form
    '  動態生成按扭
    Private myButton() As Button

    Private Sub Form_Shown(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Shown
        ' const declare
        Const x0 As Int32 = 20
        Const y0 As Int32 = 20
        Const w As Int32 = 100
        Const h As Int32 = 30
        Const hd As Int32 = 10
        Const cnt As Int32 = 4

        Dim i As Int32 = 0
        ReDim myButton(cnt)

        ' 動態生成 button
        For i = 0 To cnt - 1
            myButton(i) = New Button()
            myButton(i).Text = "button" & i
            myButton(i).Left = x0
            myButton(i).Top = y0 + i * (h + hd)
            myButton(i).Width = w
            myButton(i).Height = h
            Me.Controls.Add(myButton(i))
            AddHandler myButton(i).Click, AddressOf myButtonClick
        Next
    End Sub

    ' 委派函式
    Private Sub myButtonClick(ByVal sender As Object, ByVal e As System.EventArgs)
        System.Windows.Forms.MessageBox.Show(CType(sender, Button).Text)
    End Sub
End Class


範例四 - 動態生成 Button (3)

第三版動態生成按鈕改善了二個部份,我們可以借由自己寫的函式,把 Button Name 一次全換掉;除此之外,事實上 myButton 可以不用 array 方式建立,同時也可以不用宣告到全域。

注意的是那個 SetButtonName,它的引數記得是放 string,不要直接傳 Button 實體進去,傳 Button 實體進去的話,做法就要等 Button 全都建完之後才可以去呼叫 SetButtonName,效率不彰。

Public Class Form
    '  動態生成按扭


    ' 設定按鈕名稱
    Private Sub SetButtonName(ByRef btnName() as String, ByVal ParamArray Name() As String)
        For i As Int32 = 0 To UBound(btnName) - 1
            btnName(i) = Name(i)
        Next i
    End Sub

    Private Sub Form_Shown(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Shown

        Dim btnName() As String
        ' const declare
        Const x0 As Int32 = 20
        Const y0 As Int32 = 20
        Const w As Int32 = 100
        Const h As Int32 = 30
        Const hd As Int32 = 10
        Const cnt As Int32 = 4

        Dim i As Int32 = 0
        Dim myButton As Button

        ReDim btnName(cnt)
        SetButtonName(btnName, "OK", "ERROR", "WARNNING", "RETRY")


        ' 動態生成 button
        For i = 0 To cnt - 1
            myButton = New Button()
            myButton.Text = btnName(i)
            myButton.Left = x0
            myButton.Top = y0 + i * (h + hd)
            myButton.Width = w
            myButton.Height = h
            Me.Controls.Add(myButton)
            AddHandler myButton.click, AddressOf myButtonClick
        Next
    End Sub

    Private Sub myButtonClick(ByVal sender As Object, ByVal e As System.EventArgs)
        System.Windows.Forms.MessageBox.Show(CType(sender, Button).Text)
    End Sub
End Class

總結

動態生成子控制大致上就像上述那樣,這裡提醒的是,如果每個 Button 實際上做的動態差很多,可以考慮把 myButton 宣告成陣列型態(這不是必然,不是用陣列去做時到時 mapping 會比較清楚、簡單),接著再手動去寫一份 map,至於 Rename 部份仍可以在建立實際 Button 時進行。最後結束前,再給最後一個範例,說明建立四個 button,名稱差很多,處理的東西也差很多,寫出來會是怎樣。

Public Class Form
    '  動態生成按扭

    Private Sub SetButtonName(ByRef btnName() As String, ByVal ParamArray Name() As String)
        For i As Int32 = 0 To UBound(btnName) - 1
            btnName(i) = Name(i)
        Next i
    End Sub

    Private Sub Form_Shown(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Shown
        Dim BtnName() As String
        ' const declare
        Const x0 As Int32 = 20
        Const y0 As Int32 = 20
        Const w As Int32 = 100
        Const h As Int32 = 30
        Const hd As Int32 = 10
        Const cnt As Int32 = 4

        Dim i As Int32 = 0
        Dim myButton As Button

        ReDim BtnName(cnt)
        SetButtonName(BtnName, "OK", "ERROR", "WARNNING", "RETRY")

        ' 動態生成 button
        For i = 0 To cnt - 1
            myButton = New Button()

            myButton.Text = BtnName(i)
            myButton.Name = "btn_" & i ' 注意,這裡視為是 button ID, 不是 button text

            myButton.Left = x0
            myButton.Top = y0 + i * (h + hd)
            myButton.Width = w
            myButton.Height = h
            Me.Controls.Add(myButton)
            AddHandler myButton.Click, AddressOf myButtonClick
        Next
    End Sub

    Dim btnIndex As Int32
    Private Sub myButtonClick(ByVal sender As Object, ByVal e As System.EventArgs)

        ' 取得是由哪個 button ID 發出來的訊息
        btnIndex = Val(CType(sender, Button).Name.Split("_")(1))

       ' 根據發出來的 button ID 做相對應的 function map,這部份比較麻煩
       Select Case btnIndex
            Case 0
                Func0()
            Case 1
                Func1()
            Case 2
                Func2()
            Case 3
                Func3()
        End Select
    End Sub


    Public Sub Func0()
        MsgBox("func0")
    End Sub


    Public Sub Func1()
        MsgBox("func1")
    End Sub

    Public Sub Func2()
        MsgBox("func2")
    End Sub

    Public Sub Func3()
        MsgBox("func3")
    End Sub

    Public Sub Func4()
        MsgBox("func4")
    End Sub
End Class

沒有留言:

張貼留言