ドッキングする側のウィンドウ DockContent

ドッキング ウィンドウは、DockContentを継承したフォームとして作成します。なおこのクラスは、System.Windows.Forms.Formを継承しています。

DockContentの作成

正規の方法

ソリューション エクスプローラ上でプロジェクトを右クリックし、[追加]の[新しい項目]を選択します。そして[Windows Forms]のカテゴリから[継承されたフォーム]を選択します。

[継承ピッカー]ウィンドウで継承元コンポーネントを指定し、[参照]をクリックします。

「WeifenLuo.WinFormsUI.Docking.dll」ファイルを開きます。

DLLに含まれるコンポーネントから、[DockContent]を指定します。

これで、DockContentを継承したフォームが作成されます。

簡単な方法

  1. ソリューション エクスプローラ上でプロジェクトを右クリックし、[追加]の[Windows フォーム]を選択する。
  2. 作成されたフォームの型を、Formから[WeifenLuo.WinFormsUI.Docking.DockContent]へ変更する。
public partial class MyDockContent : WeifenLuo.WinFormsUI.Docking.DockContent
{
}

既存のコントロールをドッキング可能にする方法

FormやUserControlを継承したコントロールならば、その基本クラスをDockContentに変更するだけです。そうではないならば、そのコントロールを格納するDockContentを作成した上で、そのDockContentをドッキング ウィンドウとして表示します。

private MyControl myControl;
private WeifenLuo.WinFormsUI.Docking.DockContent myControlContainer; // コントロールのコンテナ


myControlContainer = new WeifenLuo.WinFormsUI.Docking.DockContent();
myControlContainer.Controls.Add(myControl); // コンテナにコントロールを追加
myControlContainer.Show(dockPanel);         // コンテナをドッキング可能として表示

DockContentの表示

DockPanelをShow()の引数に渡して表示することで、それにドッキングできるようになります。逆にDockPanelを指定せずに表示すると、どこにもドッキングできません。

public partial class Form1 : Form
{
    private WeifenLuo.WinFormsUI.Docking.DockPanel dockPanel;
    private MyDockContent myDockContent;

    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);

        // dockPanelがMDIの子コントロールではないとき、DocumentStyleが既定のDockingMdiのままDockContentを表示すると、InvalidOperationExceptionとして例外が投げられる
        dockPanel.DocumentStyle = DocumentStyle.DockingWindow;

        myDockContent = new MyDockContent();
        myDockContent.Show(dockPanel);
    }
}

DockPanelにテーマが設定されていないと、Show()の呼び出しで「DockPanel.Theme must be set to a valid theme.」としてArgumentExceptionが投げられます。

メソッド 機能
void Show(DockPanel dockPanel) dockPanelにドッキング可能な状態で、設定済みのDockStateで表示

設定済みのDockStateが"Unknown"または"Hidden"だと、「Invalid DockState: Content can not be showed as "Unknown" or "Hidden".」としてArgumentExceptionが投げられる。よってDockStateを指定した方が安全

void Show(DockPanel dockPanel, DockState dockState) dockPanelにドッキング可能な状態で、指定のdockStateで表示
void Show(DockPanel dockPanel, Rectangle floatWindowBounds) dockPanelにドッキング可能な状態で、floatWindowBoundsの大きさで、フロートウィンドウとして表示
void Show(DockPane pane, IDockContent beforeContent) pane区画の、beforeContentより前に表示
void Show(DockPane previousPane, DockAlignment alignment, double proportion) previousPane区画のalignmentの位置に、proportionの割合だけずらして表示

複数のDockContentの表示

複数のDockContentを同一のDockPanelに表示した場合、後から表示したものが右または下のタブに表示され、最後のものが最初にアクティブになります。

通常とは逆に、前へ追加するには次のようにします。

dockPanel2.Show(dockPanel1.Pane, dockPanel1);

既存のDockContentと同一の区画へ、位置をずらして追加するには次のようにします。

double proportion = 0.5;
dockPanel2.Show(dockPanel1.Pane, DockAlignment.Bottom, proportion);

指定の区画への追加

追加位置 追加方法
上下左右の同一位置の中の先頭の区画、の末尾
myDockContent.Show(dockPanel, DockState.DockRight);
指定区画、の先頭
myDockContent.Show(dockPanel.Pane, dockPanel);
上記以外、の末尾
myDockContent.Show(dockPanel, dockPanel.Pane.DockState);
myDockContent.Pane = dockPanel.Pane;

非表示にされたウィンドウの表示

非表示にされたウィンドウをプログラムから表示するには、Show()を呼ぶだけです。しかしAutoHideの状態のウィンドウはタブが表示されるだけのため、表示されたことを視認しづらいです。この問題には、親ウィンドウのActiveAutoHideContentに自身を設定し展開することで対処できます。c# - Calling up DockPanel-Suite's "AutoHidden" DockContent programmatically - Stack Overflow

myDockContent.Show();

if (myDockContent.DockState == DockState.DockTopAutoHide
    || myDockContent.DockState == DockState.DockBottomAutoHide
    || myDockContent.DockState == DockState.DockLeftAutoHide
    || myDockContent.DockState == DockState.DockRightAutoHide)
{
    // アクティブなウィンドウとして設定することで、閉じられた状態を展開させる
    myDockContent.DockPanel.ActiveAutoHideContent = myDockContent;

    // 再び閉じられないように、実際にアクティブにする
    myDockContent.Activate();
}

Formとの相違

DockContentはFormを継承していますが、Show()とHide()はnewで隠蔽されているためFormのそれとは動作が異なります。FormではVisibleプロパティを設定するだけであり、このプロパティを直接設定しても同じです。一方でDockContent.Show()はDockHandler.Show()を呼ぶだけであり、それは

public void Show()
{
    if (DockPanel == null)
        Form.Show();
    else
        Show(DockPanel);
}

のように実装されているため、ドッキング ウィンドウの親であるDockPanelが設定されているならばShow(DockPanel)が呼び出されます。またDockContent.Hide()はDockHandler.Hide()を呼び、それは

public void Hide()
{
    IsHidden = true;
}

であることから、IsHiddenへの設定となります。このときVisibleには設定されないためVisibleChangedは発生せず、DockStateChangedが発生します。

Visibleプロパティはnewで隠蔽されておらずForm.Visibleへの設定と同じため、Formとは異なりShow()とHide()の呼び出しとは異なる結果となります。

フロート ウィンドウとして表示するときのサイズの指定

引数でDockState.Floatとして表示するとフロート ウィンドウとして表示されますが、

myDockContent.Show(dockPanel, DockState.Float);

そのときのサイズはDockPanelクラスのDefaultFloatWindowSizeプロパティの定義

public Size DefaultFloatWindowSize { get; set; } = new Size(300, 300);

により、300x300に設定されます。これをサイズを指定して表示するにはRectangleを渡して

myDockContent.Show(dockPanel, myDockContent.Bounds);

とします。このオーバーロードは内部でDockState.Floatを引数に取るShow()を呼ぶため、この方法でもフロート ウィンドウとなります。

表示せずに、ドッキングの状態のみを指定

後で表示するためにドッキングの位置のみを指定するには、Show()を呼ばずプロパティに設定します。たとえば、

myDockContent.Show(dockPanel, DockState.DockRight);

と表示するときの状態を指定するには

myDockContent.DockPanel = dockPanel;
myDockContent.ShowHint = DockState.DockRight;
// myDockContent.Pane = ドッキングする区画

とします。一方で、

myDockContent.Show(previousPane, DockAlignment.Bottom, 0.5);

のように指定区画に表示する場合は

myDockContent.DockPanel = previousPane.DockPanel;
myDockContent.Pane = previousPane.DockPanel.Theme.Extender.DockPaneFactory.CreateDockPane(myDockContent, previousPane, DockAlignment.Bottom, 0.5, false);

のようにCreateDockPane()から設定します。

プロパティ

プロパティ 内容
bool AllowRedocking trueならば、ドラッグアンドドロップによって再びドッキングすることを許可
double AutoHidePortion AutoHideモードで表示されるときの表示サイズの割合。有効な数値は0.0~1.0の間で、既定値は0.25
bool CloseButton trueならば、[閉じる]ボタンが有効
DockAreas DockableAreas DockAreas ドッキング可能な領域
DockContentHandler DockHandler  
DockPanel DockPanel ドッキング ウィンドウの親

これに設定するとウィンドウが表示される。

親が変更されるときにControl.AssignParent()が呼ばれ、それによりVisibleChangedや、FontChangedなどが呼ばれることがある AssignParent - Control.cs

DockState DockState ドッキング状態
DockState ShowHint 初回に表示するときのドッキング位置
DockState VisibleState 可視でのドッキング状態。非表示にされる前の状態が保持されている

DockStateプロパティがHiddenに変更されたときは、その前の状態。それ以外ではDockStateと同じ

bool HideOnClose trueならば、ウィンドウを閉じるように指示されたときに、閉じずに非表示とする
bool IsActivated trueならば、現在アクティブ
bool IsFloat trueならば、フロート ウィンドウ。つまりVisibleStateがDockState.Floatである
bool IsHidden trueならば、非表示

これはDockStateプロパティがHiddenであることを意味していて、タブで他のウィンドウに隠れていたり、AutoHideで隠れていてもtrueとはならない

Hide()を呼び出すことは、IsHiddenをtrueとすることと同じ

bool Visible (Controlから継承) 次の状態のときに、false
  • DockStateプロパティがHidden
  • タブで他のウィンドウに隠れている
  • AutoHideにされてから表示されていない。1度表示されると、隠されてもtrueのまま
DockPane Pane 現在の区画
DockPane PanelPane ドッキングされる区画
DockPane FloatPane フロートでの区画
string TabText DockPaneのタブに表示する文字列。これが設定されていない場合は、Textプロパティの値が用いられる

イベント

派生元のFormに対し、追加で実装されているのは下表のイベントのみです。

イベント 発生タイミング
EventHandler DockStateChanged DockStateが変更されたとき

SizeChanged

AutoHideで隠されたり表示されたりすることを通知するイベントはありませんが、そのときウィンドウのサイズが変化することからそれを検知できます。隠されるときにはSizeChangedイベントが2度発生します。上端または下端にドッキングしているときは1度目にHeightだけがゼロとなり、2度目にWidthもゼロとなります。左右の端では、1度目にWidthがゼロとなります。

トラブル対処法

不正なスケーリング

フォントを基準とした自動スケーリング (AutoScaleMode.Font) を適用しているとき、DockPanelの親フォームのフォントを変更すると、DockContentの子コントロールのスケーリングが正しく処理されないことがあります。そのときには次のいずれかの方法で対処します。

  • DockContentの表示前に、親フォームと同一のフォントを指定する
    myDockContent = new MyDockContent();
    
    myDockContent.Font = this.Font;
    myDockContent.Show(panel1, DockState.Float);
    
  • 子コントロールをすべて、Panelなどの他のコントロール内に配置する
  • PatchController.EnableFontInheritanceFix = falseとして、DockPanelのフォントが子コントロールに波及しないようにする

タブのボタン

DockPaneのタブのボタンはスケーリングが考慮されていないため、DockPaneを表示後に変更すると不適切に表示されます。c# - Resize dock pane tab strip text and buttons in Document docked DockContent - Stack Overflow

FormClosedイベントが発生しない

親ウィンドウが閉じられるときにFormClosedイベントが発生しないならば、ドッキングする側のウィンドウのClose()を明示的に呼ぶようにします。これはDockPanel Suiteのバグであり、DocumentStyleを指定しても解決できません。Documents' FormClosed() event is not fired when DockPanel is closed · Issue #613 · dockpanelsuite/dockpanelsuite · GitHub