WPFのプロジェクトでLivetを使用していて、かつAvalonDockも使用していたときにつまづいた部分をメモ。検証用ソースはこちら
https://github.com/ambleside138/ControlsShowcase
TransitionInteractionMessageAction
LivetのTransitionInteractionMessageActionを利用すると、ViewModelから子ウィンドウを表示することができます
<l:InteractionMessageTrigger MessageKey="ShowCommand" Messenger="{Binding Messenger}">
<!-- Window を表示するメッセージアクション -->
<l:TransitionInteractionMessageAction WindowType="{x:Type local:ChildWindow}"
Mode="Modal" />
</l:InteractionMessageTrigger>
Messenger.Raise(new TransitionMessage("ShowCommand"));
簡単です。
が、これをAvalonDockで利用するときには何点か注意事項があります。
InvokeActionOnlyWhenWindowIsActiveプロパティの指定
メッセージアクションを記述しているコントロールが属しているAvalonDockのパネルがFloatingWindow化されている場合、そのウィンドウのIsActiveプロパティがfalseを返しているようです。そのため、InvokeActionOnlyWhenWindowIsActiveプロパティをFalseに指定しておかないと子ウィンドウが表示されなくなってしまいます。
<l:InteractionMessageTrigger MessageKey="ShowCommand" Messenger="{Binding Messenger}">
<!-- Window を表示するメッセージアクション -->
<!-- AvalonDockでフローティングウィンドウ化されているときはInvokeActionOnlyWhenWindowIsActive=FalseにしないとInvokeされなくなる -->
<l:TransitionInteractionMessageAction WindowType="{x:Type local:ChildWindow}"
InvokeActionOnlyWhenWindowIsActive="False"
Mode="Modal" />
</l:InteractionMessageTrigger>
CenterOwner
子ウィンドウのWindowStartupLocationプロパティをCenterOwnerとすると、子ウィンドウの初期位置がメッセージアクションを記述しているコントロールが属するウィンドウの中央に設定されます。が、FloatingWindow化されているときはドッキング状態でのウィンドウの中央に表示されてしまうようです。
「通常のTransitionInteractionMessageAction」ボタンを押下したとき
そこでTransitionInteractionMessageActionを継承して、FloatingWindowの中央に子ウィンドウが表示されるようにしました。TransitionInteractionMessageAction内で
targetWindow.Owner = Window.GetWindow(AssociatedObject);
としている部分でFloatingWindowが設定されるように変更してます。
ポイントはこのメソッド↓
// AvalonDock使用時にFloatingWindowを親にしたい
private Window GetParentWindow4Avalon(DependencyObject dp)
{
if (dp == null)
{
return null;
}
if (dp is Window)
{
return dp as Window;
}
else if( dp is LayoutAnchorableControl)
{
var model = ((LayoutAnchorableControl)dp).Model as LayoutAnchorable;
var parentFloatingWindow = model.FindParent<LayoutAnchorableFloatingWindow>();
if (parentFloatingWindow != null)
{
return model.Root.Manager.FloatingWindows.Single(fwc => fwc.Model == parentFloatingWindow);
}
// ドッキング状態の場合はいつも通りGetWindowする
else
{
return Window.GetWindow(AssociatedObject);
}
}
return GetParentWindow4Avalon(VisualTreeHelper.GetParent(dp));
}
Actionを記述しているコントロールの親がLayoutAnchorableControlである場合に、FloatingWindow化されているかどうかを確認して、FloatingWindow化されていればそちらを返すようにしてます。こうすることで、子ウィンドウの位置を意図した位置に表示できるようになりました。
「TransitionInteraction4AvalonDockMessageAction」ボタンを押下したとき
以上です。