Panelを継承したクラスで、AutoScrollをTrueにすると子コントロールが縮む

詳細はここ

環境

WindowsXP Pro SP3
VisualStudio 2008
.NET Framework3.5

現象

Public Class MyPanel
  Inherits System.Windows.Forms.Panel

End Class

のように単純にパネルを継承したクラスを作成し、パネル内にコントロールを配置。
コントロールのAnchorをTop, Left, Rightに設定しておく。
さらに、MyPanelのAutoScrollプロパティをTrueにするとパネル内の子コントロールが縮む。
どうやらスクロールバーの分が2重にリサイズされている模様。

対応策 (以下はベストではない。最新情報は後日 または ここを参照)

とりあえず、パネル側にISupportInitializeを実装してやって回避することに。

Public MustInherit Class MyPanelBase
  Inherits System.Windows.Forms.Panel
  Implements System.ComponentModel.ISupportInitialize

  Private _RightAnchorControls As List(Of Control)
  Private _BottomAnchorControls As List(Of Control)

  Protected Overridable Sub BeginInit() Implements System.ComponentModel.ISupportInitialize.BeginInit
    ' Do nothing
  End Sub

  Protected Overridable Sub EndInit() Implements System.ComponentModel.ISupportInitialize.EndInit

    If (Me.AutoScroll) Then
      _RightAnchorControls = New List(Of Control)
      _BottomAnchorControls = New List(Of Control)
      For Each ctrl As Control In Me.Controls
        ' 継承コントロールの場合は、ここでctrl.Nameがクラス名になっている。何故?
        ' まぁ、継承コントロールのインスタンスが取得できていないのは間違いない。
        If ((ctrl.Anchor And (AnchorStyles.Right Or AnchorStyles.Left)) = _
          (AnchorStyles.Right Or AnchorStyles.Left)) Then
          ' Anchor が LeftかつRightのコントロールをリストアップ
          _RightAnchorControls.Add(ctrl)
          ' Anchor が LeftかつRightのコントロールからRightアンカーを外す
          ' HandleCreatedイベントで戻す
          ctrl.Anchor = (ctrl.Anchor Xor AnchorStyles.Right)
        End If
        If ((ctrl.Anchor And (AnchorStyles.Top Or AnchorStyles.Bottom)) = _
          (AnchorStyles.Top Or AnchorStyles.Bottom)) Then
          ' Anchor が TopかつBottomのコントロールをリストアップ
          _BottomAnchorControls.Add(ctrl)
          ' Anchor が TopかつBottomのコントロールからBottomアンカーを外す
          ' HandleCreatedイベントで戻す
          ctrl.Anchor = (ctrl.Anchor Xor AnchorStyles.Bottom)
        End If
      Next
    End If
  End Sub

  Protected Overrides Sub OnHandleCreated(ByVal e As System.EventArgs)
    MyBase.OnHandleCreated(e)
    If (_RightAnchorControls IsNot Nothing) Then
      ' Anchor が LeftかつRightであったコントロールのRightアンカーを戻す
      For Each ctrl As Control In _RightAnchorControls
        If (Me.Controls.Contains(ctrl)) Then ctrl.Anchor = (ctrl.Anchor Or AnchorStyles.Right)
      Next
      _RightAnchorControls = Nothing
    End If

    If (_BottomAnchorControls IsNot Nothing) Then
      ' Anchor が TopかつBottomであったコントロールのBottomアンカーを戻す
      For Each ctrl As Control In _BottomAnchorControls
        If (Me.Controls.Contains(ctrl)) Then ctrl.Anchor = (ctrl.Anchor Or AnchorStyles.Bottom)
      Next
      _BottomAnchorControls = Nothing
    End If
  End Sub
 
End Class

だがしかし、これだけでは不十分であった。
標準のTextBox等を配置する分には問題ないが、
UserControlを継承したコンポーネントを配置するとやはり縮んでしまう。*1
カスタムコントロール側にも以下のような仕込みを入れてやることにする。

Public Class MyControl
  Inherits System.Windows.Forms.UserControl
  Inherits System.ComponentModel.ISupportInitialize
  ' HACK : ISupportInitializeNotificationの実装も検討した方が良いのか…?

  Private _Size As Size
  private _IsInitialized As Boolean
  
  Protected Sub BeginInit() Implements System.ComponentModel.ISupportInitialize.BeginInit
    _IsInitialized = False
  End Sub

  Protected Sub EndInit() Implements System.ComponentModel.ISupportInitialize.EndInit
    _Size = Me.Size
    _IsInitialized = True
  End Sub

  Private Sub MyControl_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Resize
    If (_IsInitialized = True AndAlso Me.IsHandleCreated = False) Then
      Me.Size = _Size
    End If
  End Sub
End Class

これで何とか解決。


でも、
DataGridViewとかはISupportInitializeを実装済みな上に隠蔽されている。
どうしようかな…。

*1:TextBox等を継承したコントロールでは試していないが、多分同様であろう