LoginSignup
8
5

More than 5 years have passed since last update.

Livet+AvalonDockな環境での注意点

Posted at

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>
AvalonDockContainerViewModel.cs
Messenger.Raise(new TransitionMessage("ShowCommand"));

簡単です。
が、これをAvalonDockで利用するときには何点か注意事項があります。

InvokeActionOnlyWhenWindowIsActiveプロパティの指定

メッセージアクションを記述しているコントロールが属しているAvalonDockのパネルがFloatingWindow化されている場合、そのウィンドウのIsActiveプロパティがfalseを返しているようです。そのため、InvokeActionOnlyWhenWindowIsActiveプロパティをFalseに指定しておかないと子ウィンドウが表示されなくなってしまいます。

AvalonDockContainer.xaml
        <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化されているときはドッキング状態でのウィンドウの中央に表示されてしまうようです。

キャプチャ.PNG
「通常のTransitionInteractionMessageAction」ボタンを押下したとき

そこでTransitionInteractionMessageActionを継承して、FloatingWindowの中央に子ウィンドウが表示されるようにしました。TransitionInteractionMessageAction内で
targetWindow.Owner = Window.GetWindow(AssociatedObject);
としている部分でFloatingWindowが設定されるように変更してます。
ポイントはこのメソッド↓

TransitionInteraction4AvalonDockMessageAction.cs
        // 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化されていればそちらを返すようにしてます。こうすることで、子ウィンドウの位置を意図した位置に表示できるようになりました。

キャプチャ2.PNG
「TransitionInteraction4AvalonDockMessageAction」ボタンを押下したとき

以上です。

8
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
5