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 メソッドに注目してください。
<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 } }
<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 } }