2012年6月29日 星期五

WinForm 中使用 RadioButtonList


RadioButtonList 在 ASP.NET 中是再平常不過的控制項
但在 WinForm 中卻怎樣也找不著
若要在 WinForm 使用一個以上的 RadioButton
最常見的做法就是用一個 GroupBox 或 Panel 把多個 RadioButton 包起來
要取值時再跑迴圈去遍歷

但...若不確定有多少的 RadioButton 時...要怎麼預先拉 RadioButton 的數量?
可否從資料庫撈資料以 DataBind 的方式來產生 RadioButton 的數量
這時又需要撰寫 User Control

做法如下
##CONTINUE##

Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Drawing
Imports System.Data
Imports System.Text
Imports System.Windows.Forms
Imports System.Collections
Imports tw.org.mirdc

Partial Public Class RadioButtonList
    Inherits UserControl

#Region "Variable"
    Private _dataSource As [Object]
    Private _mappings As ButtonValueMapping()
    Private _internalDataSource As [Object]
    Private _displayMember As String
    Private _valueMember As String
    Private _selectedValue As String
    Private _selectedName As String
#End Region

#Region "ctor."
    Public Sub New()
        InitializeComponent()
    End Sub
#End Region

#Region "prop"
    Public Property DataSource() As System.Object
        Get
            Return _dataSource
        End Get
        Set(ByVal value As System.Object)
            _dataSource = value
        End Set
    End Property

    Public Property DisplayMember() As String
        Get
            Return _displayMember
        End Get
        Set(ByVal value As String)
            _displayMember = value
        End Set
    End Property

    Public Property ValueMember() As String
        Get
            Return _valueMember
        End Get

        Set(ByVal value As String)
            _valueMember = value
        End Set

    End Property

    Public Property SelectedValue() As String
        Get
            Return _selectedValue
        End Get

        Set(ByVal value As String)
            If value IsNot Nothing Then
                _selectedValue = value
                SetValue(value)
            End If
        End Set
    End Property

    Public Property SelectedName() As String
        Get
            Return _selectedName
        End Get
        Set(ByVal value As String)
            If value IsNot Nothing Then
                _selectedName = value
                SetValue(value)
            End If
        End Set
    End Property
#End Region

#Region "event"
    Public Delegate Sub RadioSelectedHandler(ByVal sender As Object, ByVal e As SelectedEventArgs)
    Public Event RadioItemSeleted As RadioSelectedHandler
#End Region

#Region "public method"
    Public Sub DataBind()
        If _dataSource Is Nothing Then
            Throw New NullReferenceException("Null reference in Property: DataSource ")
        End If
        PrepareData()
        DrawControl()
    End Sub
#End Region

#Region "internal function"
    Private Sub DrawControl()
        Panel1.Controls.Clear()
        Dim count As Integer = _mappings.Length
        Dim height As Integer = 0
        Dim width As Integer = 0
        Dim x_aris As Integer = 0
        Dim y_aris As Integer = 0
        For i As Integer = 0 To count - 1
            Dim radio As New RadioButton()
            radio.Name = i.ToString()
            radio.Text = _mappings(i).Text
            radio.AutoSize = True
            Panel1.Controls.Add(radio)
            height += radio.Height
            radio.Location = New Point(x_aris + width, y_aris)
            width += radio.Width
            AddHandler radio.Click, New EventHandler(AddressOf radio_Click)
        Next
        If count > 0 Then
            Panel1.Height = DirectCast(Panel1.Controls(_mappings(0).Index.ToString()), RadioButton).Height
            Me.Height = Panel1.Height
            Me.Panel1.Width = width
            Me.Width = width
        End If
    End Sub  

    Private Sub PrepareData()
        _internalDataSource = Nothing
        If TypeOf _dataSource Is DataTable Then
            _internalDataSource = DirectCast(_dataSource, DataTable).DefaultView
        End If
        If TypeOf _dataSource Is DataView Then
            _internalDataSource = _dataSource
        ElseIf TypeOf _dataSource Is List(Of mirdc.Entity.LookupTable) Then
            _internalDataSource = _dataSource
        End If
        If _internalDataSource Is Nothing Then
            Throw New InvalidCastException("The data source is not a desinged type.")
        End If
        If TypeOf _internalDataSource Is DataView Then
            Dim radioCount As Integer = DirectCast(_internalDataSource, DataView).Count
            _mappings = New ButtonValueMapping(radioCount - 1) {}
            Try
                For i As Integer = 0 To radioCount - 1
                    _mappings(i).Index = i
                    _mappings(i).Text = DirectCast(_internalDataSource, DataView)(i)(_displayMember).ToString()
                    If _valueMember Is Nothing OrElse _valueMember = String.Empty Then
                        _mappings(i).Value = i.ToString()
                    Else
                        _mappings(i).Value = DirectCast(_internalDataSource, DataView)(i)(_valueMember).ToString()
                    End If
                Next
            Catch e As Exception
                Throw e
            End Try
        End If
    End Sub

    Private Sub radio_Click(ByVal sender As Object, ByVal e As EventArgs)
        _selectedValue = _mappings(Integer.Parse(DirectCast(sender, RadioButton).Name)).Value
        Dim se As New SelectedEventArgs()
        se.Value = _mappings(Integer.Parse(DirectCast(sender, RadioButton).Name)).Value
        RaiseEvent RadioItemSeleted(Me, se)
    End Sub

    Private Sub SetValue(ByVal value As String)
        If _mappings Is Nothing Then
            Throw New NullReferenceException("Data has not bound to the control")
        End If
        For Each map As ButtonValueMapping In _mappings
            If map.Value = value Then
                DirectCast(Panel1.Controls(map.Index.ToString()), RadioButton).Checked = True
            End If
        Next
    End Sub
#End Region

    Friend Structure ButtonValueMapping
        Public Index As Integer
        Public Value As String
        Public Text As String
    End Structure
    Public Class SelectedEventArgs
        Inherits EventArgs
        Public Value As String
    End Class
End Class

編譯完後就會在工具箱出現了,這時應該知道該怎麼用了吧? 拖拉 & 複製貼上是 programmer 的強項 CheckBoxList亦可仿製

沒有留言:

張貼留言