Panel といっても何か遊ぼうと思うと、今まで遊んだ GroupBox なんかと似たり寄ったりになってしまうので
『限定したコントロールとその派生コントロールしか受け付けない Panel』を作る試みをしてみました。
ジェネリックとコンストラクタで型を指定するやつまでできたとこで
えムナウさんに他にいい方法がないですかねぇと相談したところ、
「プロパティは?」
っていう事で、プロパティでも実装しましたが、
プロパティでやるんだったらデザイナからどう変更させるかってのを考えないといけないので
面倒なので 文字列 で入力にしました。
文字列で入力だと型のチェックとか結構めんどかったです...。
enum も考えましたが、イマイチ汎用性にかけるかなぁと思ったんです。
でも文字列は明らかに使いにくいっす。何かいい方法がないかなー。
■参考文献
Panel クラス
■実行画像
今回も何も面白いこと無いです。BorderStyle で遊んでみただけ。
Public Class PanelTest
Const PANEL_NAME As String = "Panel1"
Private Sub PanelTest_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' Panel.Controls に Add する型を限定する試み
'' RadioButton の追加しか許可しない Panel その 1
Dim p1 As MyPanel(Of RadioButton) = New MyPanel(Of RadioButton)
With p1
.Name = PANEL_NAME
.Location = New Point(10, 10)
.Size = New Size(200, 60)
.BackColor = Color.LightBlue
.BorderStyle = BorderStyle.None
End With
Me.Controls.Add(p1)
Dim rdoFujiko As RadioButton = New RadioButton()
With rdoFujiko
.Location = New Point(10, 10)
.Text = "ふじこ"
End With
p1.Controls.Add(rdoFujiko)
Dim rdoEden As RadioButton = New MyRadioButton()
With rdoEden
.Location = New Point(10, 30)
.Text = "えでん"
End With
p1.Controls.Add(rdoEden)
Try
p1.Controls.Add(New ComboBox()) ' 作為的に発生
Catch ex As ArgumentException
System.Diagnostics.Debug.WriteLine(ex.Message)
End Try
'' RadioButton の追加しか許可しない Panel その 2
Dim p2 As MyPanel2 = New MyPanel2(GetType(RadioButton))
With p2
.Location = New Point(10, 90)
.Size = New Size(200, 60)
.BackColor = Color.LightYellow
.BorderStyle = BorderStyle.FixedSingle
End With
Me.Controls.Add(p2)
Try
p2.Controls.Add(New TextBox()) ' 作為的に発生
Catch ex As ArgumentException
System.Diagnostics.Debug.WriteLine(ex.Message)
End Try
'' RadioButton の追加しか許可しない Panel その 3
Dim p3 As MyPanel3 = New MyPanel3()
With p3
.TypeString = GetType(RadioButton).FullName
.Location = New Point(10, 170)
.Size = New Size(200, 60)
.BackColor = Color.LightSalmon
.BorderStyle = BorderStyle.Fixed3D
End With
Me.Controls.Add(p3)
Try
p3.Controls.Add(New ListBox()) ' 作為的に発生
Catch ex As ArgumentException
System.Diagnostics.Debug.WriteLine(ex.Message)
End Try
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim pnl As MyPanel(Of RadioButton) = DirectCast(Me.Controls(PANEL_NAME), MyPanel(Of RadioButton))
' For Each で回す
For Each r As RadioButton In pnl.Controls
System.Diagnostics.Debug.WriteLine(r.Text & ":" & r.Checked.ToString())
Next
End Sub
End Class
' こいつはただ継承しただけ
Public Class MyRadioButton
Inherits RadioButton
End Class
' ジェネリックを使う
' (デザイナで操作不可)
Public Class MyPanel(Of T As System.Windows.Forms.Control)
Inherits System.Windows.Forms.Panel
Protected Overrides Sub OnControlAdded(ByVal e As System.Windows.Forms.ControlEventArgs)
If TypeOf e.Control Is T Then
MyBase.OnControlAdded(e)
Else
MyBase.Controls.Remove(e.Control)
Throw New ArgumentException(e.Control.GetType.FullName & ":このパネルに追加するコントロールは " & _
GetType(T).FullName & " またはその派生クラスでなければなりません")
End If
End Sub
End Class
' コンストラクタで型指定
' (デザイナで操作可能・しかしデザイナで貼り付けた場合は通常の Panel と何ら変わり無い)
Public Class MyPanel2
Inherits System.Windows.Forms.Panel
Private m_Type As Type = GetType(System.Windows.Forms.Control)
Public Sub New(ByVal t As Type)
MyBase.New()
If Not IsBasedOnValidClass(t, GetType(System.Windows.Forms.Control)) Then Throw New ArgumentException("Control を継承した型でなければなりません")
Me.m_Type = t
End Sub
Protected Overrides Sub OnControlAdded(ByVal e As System.Windows.Forms.ControlEventArgs)
If IsBasedOnValidClass(e.Control.GetType(), Me.m_Type) Then
MyBase.OnControlAdded(e)
Else
MyBase.Controls.Remove(e.Control)
Throw New ArgumentException(e.Control.GetType.FullName & ":このパネルに追加するコントロールは " & _
Me.m_Type.FullName & " またはその派生クラスでなければなりません")
End If
End Sub
Private Function IsBasedOnValidClass(ByVal t As Type, ByVal validBaseType As Type) As Boolean
If t Is validBaseType Then Return True
If t.BaseType Is Nothing Then Return False
Return IsBasedOnValidClass(t.BaseType, validBaseType)
End Function
End Class
' プロパティで型指定
' (デザイナで操作可能・しかし TypeString に何も指定しない場合は通常の Panel と何ら変わり無い)
Public Class MyPanel3
Inherits System.Windows.Forms.Panel
Private m_typeString As String = GetType(System.Windows.Forms.Control).FullName
Private m_type As Type = GetType(System.Windows.Forms.Control)
< System.ComponentModel.Browsable(True), System.ComponentModel.ReadOnly(False), _
System.ComponentModel.Description("追加を許可するコントロールの型を FullName で指定します") > _
Public Property TypeString() As String
Get
Return Me.m_typeString
End Get
Set(ByVal value As String)
If String.IsNullOrEmpty(value) Then Throw New ArgumentException("値を Null にする事はできません")
Dim tp As Type = Nothing
' 自身のアセンブリから型を検索
tp = System.Reflection.Assembly.GetExecutingAssembly.GetType(value, False)
If tp Is Nothing Then
' なければ次に System.Windows.Forms.dll より型を検索
Dim foundControl As Object = GetType(System.Windows.Forms.Control).Assembly.CreateInstance(value, False)
If Not foundControl Is Nothing Then tp = foundControl.GetType()
End If
If tp Is Nothing Then Throw New ArgumentException("型の文字列に誤りがあります")
If Not IsBasedOnValidClass(tp, GetType(System.Windows.Forms.Control)) Then Throw New ArgumentException("Control を継承した型でなければなりません")
Me.m_type = tp
Me.m_typeString = value
End Set
End Property
Protected Overrides Sub OnControlAdded(ByVal e As System.Windows.Forms.ControlEventArgs)
If IsBasedOnValidClass(e.Control.GetType(), Me.m_type) Then
MyBase.OnControlAdded(e)
Else
MyBase.Controls.Remove(e.Control)
Throw New ArgumentException(e.Control.GetType.FullName & ":このパネルに追加するコントロールは " & _
Me.m_type.FullName & " またはその派生クラスでなければなりません")
End If
End Sub
Private Function IsBasedOnValidClass(ByVal t As Type, ByVal validBaseType As Type) As Boolean
If t Is validBaseType Then Return True
If t.BaseType Is Nothing Then Return False
Return IsBasedOnValidClass(t.BaseType, validBaseType)
End Function
End Class