Q077. コードビハインドを使わずに親から子に画面遷移するには?

A.Livet を使うとコードビハインドを使わずに画面遷移が可能になります。Livet では画面遷移のメッセージアクションが提供されているので、これを使うといいでしょう。


ケースよっては、子画面を起動したら親画面を非表示にしたい場合もあります。その場合も、親画面のインスタンスさえ取得できれば、コードビハインドを使わず実装可能です。現在の View のインスタンスは、以下の方法で取得できます。

var window = Application.Current.Windows.OfType<Window>().SingleOrDefault((w) => w.IsActive);

これに Livet の画面遷移用メッセージアクションと組み合わせれば、親画面から子画面を遷移できます。

注) Livet 1.0.4 以降、Window を非表示にしてメッセージを送信するには TransitionInteractionMessageAction.InvokeActionOnlyWhenWindowIsActive プロパティを False に設定が必要になりましたので注意してください。


サンプル

以下サンプルです。親画面のボタンをクリックすると子画面をモーダル表示し、親は非表示になります。子画面を閉じると親を再表示します。MainWindowViewModel の Show メソッドに注目してください。


親画面の View

<Window x:Class="LivetWPFApplication1.Views.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        xmlns:l="http://schemas.livet-mvvm.net/2011/wpf"
        xmlns:v="clr-namespace:LivetWPFApplication1.Views"
        xmlns:vm="clr-namespace:LivetWPFApplication1.ViewModels"
        Title="親" Height="200" Width="350" 
        WindowStartupLocation="CenterScreen">
    
    <Window.DataContext>
        <vm:MainWindowViewModel/>
    </Window.DataContext>

    <i:Interaction.Triggers>
        <l:InteractionMessageTrigger MessageKey="ShowCommand" Messenger="{Binding Messenger}">
            <!-- Window を表示するメッセージアクション 
                 Window を非表示にしてもメッセージを送信できるようにするには InvokeActionOnlyWhenWindowIsActive="False" が必要 -->
            <l:TransitionInteractionMessageAction WindowType="{x:Type v:Window1}" Mode="Modal"
                                                  InvokeActionOnlyWhenWindowIsActive="False" />
        </l:InteractionMessageTrigger>
    </i:Interaction.Triggers>

    <Grid>
        <Button Content="子画面を開く" Width="100" Height="28"
                Command="{Binding ShowCommand}"
                HorizontalAlignment="Center" VerticalAlignment="Center" />
    </Grid>
</Window>


親画面の ViewModel

using System.Linq;
using System.Windows;
using Livet;
using Livet.Commands;
using Livet.Messaging;

namespace LivetWPFApplication1.ViewModels {
    public class MainWindowViewModel : ViewModel {

        #region ShowCommand
        private ViewModelCommand _ShowCommand;

        public ViewModelCommand ShowCommand {
            get {
                if (_ShowCommand == null) {
                    _ShowCommand = new ViewModelCommand(Show);
                }
                return _ShowCommand;
            }
        }

        public void Show() {
            // 現在の View のインスタンスを取得
            var window = Application.Current.Windows.OfType<Window>().SingleOrDefault((w) => w.IsActive);
            try {
                // 現在の View を非表示
                window.Hide(); 
                // View にメッセージを送信〜子画面をモーダルで起動
                Messenger.Raise(new TransitionMessage(new ViewModel1(), "ShowCommand"));
            }
            finally {
                // View を再表示する
                window.ShowDialog();
            }
        }
        #endregion
    }
}


子画面の View

<Window x:Class="LivetWPFApplication1.Views.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        xmlns:l="http://schemas.livet-mvvm.net/2011/wpf"
        xmlns:v="clr-namespace:LivetWPFApplication1.Views"
        xmlns:vm="clr-namespace:LivetWPFApplication1.ViewModels"
        Title="子" Height="120" Width="240" 
        WindowStartupLocation="CenterScreen">
    
    <Window.DataContext>
        <vm:ViewModel1/>
    </Window.DataContext>

    <i:Interaction.Triggers>
        <l:InteractionMessageTrigger MessageKey="Close" Messenger="{Binding Messenger}">
            <l:WindowInteractionMessageAction/>
        </l:InteractionMessageTrigger>
    </i:Interaction.Triggers>

    <Grid>
        <Button Content="閉じる" Width="80" Height="28"
                Command="{Binding CloseCommand}"
                HorizontalAlignment="Center" VerticalAlignment="Center" />
    </Grid>
</Window>


子画面の ViewModel

using Livet;
using Livet.Commands;
using Livet.Messaging.Windows;

namespace LivetWPFApplication1.ViewModels {
    public class ViewModel1 : ViewModel {

        #region CloseCommand
        private ViewModelCommand _CloseCommand;

        public ViewModelCommand CloseCommand {
            get {
                if (_CloseCommand == null) {
                    _CloseCommand = new ViewModelCommand(Close);
                }
                return _CloseCommand;
            }
        }

        public void Close() {
            Messenger.Raise(new WindowActionMessage("Close", WindowAction.Close));
        }
        #endregion
    }
}


WPF FAQ の目次に戻る