DockPanel SuiteでFloatWindowのサイズを動的に変更する
ウィンドウをドラッグしてFloatにすると最初のサイズは、DockPanelのDefaultFloatWindowSize(デフォルトは300×300)で静的に初期化される。このサイズの変更が相当ハマったのでメモ。
いくらドッキングのときにサイズを調整してもFloatにした場合は、必ずDefaultFloatWindowSizeで初期化されてしまう。さらに、FloatになったあとにDockStateChangedのイベント等でDockContentのSizeやClientSizeを変更しても、FloatWindowには反映されない。ただし、フォームの境界線をマウスでドラッグ&ドロップして、手動でサイズを変更することはできる。
この理由は、DockState=Floatのときの、画面に表示しているフォームは、DockContentではなく、DockPanelとDockPane(とRectangle)から生成されるFloatWindowという全く別のフォームを参照している。さらにめんどいことに、FloatWindowはDockContentを継承しておらず、Formを継承するのみなので、どのContentに対して操作しているのかを示すプロパティがない。どういった問題が生じるかというと、例えば、Extenderを用いて(参考:https://github.com/dockpanelsuite/dockpanelsuite/wiki/FloatWindow)CustomFloatWindowのコンストラクタで初期化しようとすると、DockContentにアクセスできないため、容易には元のサイズを取得することができない。また、DockPanelは与えられるがFloatWindowに格納されているコントロールは、DockContentに格納されているコントロールとは一致しないため、FloatWindow側でDockPanel.Contentからコントロールのコレクションが一致するContentを抜き出す等も不可能である。唯一可能性があるのが、FloatWindowのDockPaneと、DockPanelのDockContent側のPaneが一致するかどうかをLINQ等を使って抜き出す方法。ただし、これは元のDockStateがDockment以外なら作動するが、Documentの場合FloatWindow側のDockPaneが実質上のEmpty状態なので、完全にはDockPaneからではDockContentで抜き出すことはできない。
そもそもDockContent側から、FloatWindowにアクセスする方法はないのか?というと実はあって、これがFloatWindowのサイズを動的に変更する唯一の方法かと思う。DockState=Float時のサイズ変更の処理は、DockContentのSizeに対して働きかけると見た目が変わらないが、FloatWindowのSizeに働きかければその通りにサイズが変更される。つまり、DockState=Floatのときはマウスでのサイズ変更の処理以外をブロックしているというわけではないようだ。
じゃあ、DockContentからFloatWindowにどうやってアクセスするのかというと、DockContentのインスタンスdockContent.FloatPane.FloatWindowとする。DockContentのDockStateChangedのイベントと合わせると、次のようにしてFloatWindowのサイズを自動調整することができる。
分かりやすい説明ができないけど、結論としては、FloatWindowに対して処理をするというのが重要。
いくらドッキングのときにサイズを調整してもFloatにした場合は、必ずDefaultFloatWindowSizeで初期化されてしまう。さらに、FloatになったあとにDockStateChangedのイベント等でDockContentのSizeやClientSizeを変更しても、FloatWindowには反映されない。ただし、フォームの境界線をマウスでドラッグ&ドロップして、手動でサイズを変更することはできる。
この理由は、DockState=Floatのときの、画面に表示しているフォームは、DockContentではなく、DockPanelとDockPane(とRectangle)から生成されるFloatWindowという全く別のフォームを参照している。さらにめんどいことに、FloatWindowはDockContentを継承しておらず、Formを継承するのみなので、どのContentに対して操作しているのかを示すプロパティがない。どういった問題が生じるかというと、例えば、Extenderを用いて(参考:https://github.com/dockpanelsuite/dockpanelsuite/wiki/FloatWindow)CustomFloatWindowのコンストラクタで初期化しようとすると、DockContentにアクセスできないため、容易には元のサイズを取得することができない。また、DockPanelは与えられるがFloatWindowに格納されているコントロールは、DockContentに格納されているコントロールとは一致しないため、FloatWindow側でDockPanel.Contentからコントロールのコレクションが一致するContentを抜き出す等も不可能である。唯一可能性があるのが、FloatWindowのDockPaneと、DockPanelのDockContent側のPaneが一致するかどうかをLINQ等を使って抜き出す方法。ただし、これは元のDockStateがDockment以外なら作動するが、Documentの場合FloatWindow側のDockPaneが実質上のEmpty状態なので、完全にはDockPaneからではDockContentで抜き出すことはできない。
そもそもDockContent側から、FloatWindowにアクセスする方法はないのか?というと実はあって、これがFloatWindowのサイズを動的に変更する唯一の方法かと思う。DockState=Float時のサイズ変更の処理は、DockContentのSizeに対して働きかけると見た目が変わらないが、FloatWindowのSizeに働きかければその通りにサイズが変更される。つまり、DockState=Floatのときはマウスでのサイズ変更の処理以外をブロックしているというわけではないようだ。
じゃあ、DockContentからFloatWindowにどうやってアクセスするのかというと、DockContentのインスタンスdockContent.FloatPane.FloatWindowとする。DockContentのDockStateChangedのイベントと合わせると、次のようにしてFloatWindowのサイズを自動調整することができる。
public void IMyDockingWindow_DockStateChanged(object sender, EventArgs e)
{
foreach(DockContent x in dockPanel1.Contents)
{
if(x.DockState == DockState.Float)
{
if(x.FloatPane != null)
{
//サイズの取得方法はおまかせで
//ここではサイズを提供するプロパティを持つインターフェイスを、
//全てのDockContentに実装させている
DockingWindows.IMyDockingWindow idock = x as DockingWindows.IMyDockingWindow;
x.FloatPane.FloatWindow.ClientSize = new Size(idock.RealWidth, idock.RealHeight - Config.ToolWindowTabHeight);
}
}
}
}
分かりやすい説明ができないけど、結論としては、FloatWindowに対して処理をするというのが重要。