8-2.画面遷移の骨格
戻る
従来のWindowsフォームアプリケーションの画面遷移
通常はボタンをクリックして画面遷移します。
遷画面移元(親)
1 2 3 4 5 6 7 8 9 | // 親画面で子画面を開く時 private void button1_Click( object sender, EventArgs e) { Form F = new クラス名(); F.Owner = this ; //F.ShowDialog(this); ダイアログで開く時 F.Show(); F.Owner.Hide(); } |
遷移先(子画面)
1 2 3 4 5 6 7 | // 子画面を閉じて親画面を開く時 private void button2_Click( object sender, EventArgs e) { //this.Close(); 終了する時 this .Owner.Show(); this .Close(); } |
上記の例は、Windowsフォームアプリケーションでは、親画面でButtonをWクリックして、button1_Clickメソッドを自動作成させて、その内に画面遷移のコードを書きます。子画面では「閉じる」のButtonをWクリックして、button2_Clickメソッドを自動作成させて、その内に画面遷移のコードを書きます。つまりデザイン画面でButtonをWクリックすればbuttonX_Clickメソッドが自動作成されます。WPFでも同様にClickメソッドを自動作成させて、その内に処理のコードを書くという簡単な方法はあります。(後述のコードビハインドによるコーディング)
しかし、折角、WPFを勉強するならば、次から説明するMVVMを採用すべきです。MVVMは画面とコードをファイルで分離します。そのために、ちょっとコーディング量が多くなりますが慣れれば既に書いたコードをコピーするという方法をとれば面倒さも軽減します。
ここのサンプルのダウンロード(LivetWPFApplicationBasic.lzh)WPFのMVVMでの画面遷移
Buttonクリックによる画面遷移を実装するには、
XAMLでは、
①Buttonをクリックした時のトリガーの記述
②Buttonに画面遷移の処理を記述するCommandの記述
ViewModelでは、
③遷移元画面をタスクバーに残さない記述方法
④画面遷移の処理を記述するICommandと言うメソッドの記述
が必要となります。
例ainWiえば、Mndowの「Window2へ」ボタンを押してWindow2ヘ画面遷移する例です。
Windows2が表示されても、下のタスクバーには、Window2のみが表示されて、MainWindowは表示されていません。
又、Window2を表示してからMainWindowを隠すので、画面の途切れが発生しないのでちらつきは発生しません。


MainWindowのXAMLは下記のようになります。
12~14行は、ViewとViewModelの紐付けの設定です。。
Interaction.Triggersは、
21~22行は、「Initialize」処理」を実行します。
26~28行は、「Window2への画面遷移」を実行します。
Interaction.Behaviorsは、
33~36行は、「コントロールボックスの閉じるボタンの非使用化」を実行します。
39~41行は、「「Window2への画面遷移」ボタンの実行します。
43~45行は、「「Window2への画面遷移」ボタンの実行します。
View
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | < Window x:Class = "LivetWPFApplication100.Views.MainWindow" xmlns:v = "clr-namespace:LivetWPFApplication100.Views" xmlns:vm = "clr-namespace:LivetWPFApplication100.ViewModels" xmlns:b = "clr-namespace:LivetWPFApplication100.Behaviors" Title = "MainWindow" Height = "300" Width = "450" WindowStartupLocation = "CenterScreen" > < Window.DataContext > < vm:MainViewModel /> </ Window.DataContext > < i:Interaction.Triggers > <!--WindowのContentRenderedイベントのタイミングでViewModelの Initializeメソッドが呼ばれます--> < i:EventTrigger EventName = "ContentRendered" > < l:LivetCallMethodAction MethodTarget = "{Binding}" MethodName = "Initialize" /> </ i:EventTrigger > < l:InteractionMessageTrigger MessageKey = "MessageKey2" Messenger = "{Binding Messenger}" > < l:TransitionInteractionMessageAction WindowType = "{x:Type v:Window2}" Mode = "Modal" /> </ l:InteractionMessageTrigger > </ i:Interaction.Triggers > < i:Interaction.Behaviors > < b:CloseButtonBehavior IsWindowCloseEnable = "{Binding ElementName=CloseCheck, Path=IsChecked}" /> </ i:Interaction.Behaviors > < Grid > < Button Command = "{Binding GotoCommand2}" Content = "Window2へ" Height = "32" HorizontalAlignment = "Left" Margin = "34,34,0,0" Name = "button2" VerticalAlignment = "Top" Width = "147" /> < Button Command = "{Binding CloseCommand}" Content = "終了" Height = "32" HorizontalAlignment = "Left" Margin = "319,217,0,0" Name = "button1" VerticalAlignment = "Top" Width = "97" /> </ Grid > </ Window > |
MainWindow.xamlとMainViewModel.csの紐付けは、MainWindow.xamlのコードビハインドファイルであるMainWindow.xaml.csのコンストラクタに「this.DataContext = new MainViewModel();」とも記述出来ます。
コードビハインドによるViewとViewModelの紐付け
1 2 3 4 5 | public MainWindow() { InitializeComponent(); this .DataContext = new MainViewModel(); } |
ZAMLのButton(39~41行)をクリックした時の処理(命令)はCommandと呼ばれています。このCommandはViewModelの「GotoCommand2」メソッドと紐付け(Binding)されています。
MainWindowのViewModelであるMainViewModelは下記のようになります。
GotoCommand2(ViewModel)
1 2 3 4 5 6 7 8 9 | public ViewModelCommand GotoCommand2 { get { return new Livet.Commands.ViewModelCommand(Goto2); } } public void Goto2() { Messenger.Raise( new TransitionMessage( new ViewModel2() { NeedHideOwner = true }, "MessageKey2" )); } |
ZAMLのButton(43~45行)をクリックした時の処理(命令)は「CloseCommand」メソッドと紐付け(Binding)されています。
CloseCommand(ViewModel)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | private ViewModelCommand _CloseCommand; public ViewModelCommand CloseCommand { get { if (_CloseCommand == null ) { _CloseCommand = new ViewModelCommand(Close); } return _CloseCommand; } } public void Close() { var window = Application.Current.Windows.OfType<Window>().SingleOrDefault((w) => w.IsActive); } |
遷移先のWindow2のXAMLは下記のようになります。太字部分(LoadedやClosing)はMVVMパターンでは有名な Expression Blend SDK に含まれる System.Windows.Interactivity.dll のクラス (EventTrigger, InvokeAction, Interaction 等)を使用してWPFのコントロールのイベントとViewModel等で公開される ICommand を実装したコマンドプロパティをコードビハインドファイルやハンドラを使用せずにxaml上で関連付ける方法 でSystem.Windows.Interactivity名前空間の EventTrigger クラスの EventName に コマンドと関連付けるイベントを設定し、 InvokeCommandAction によりコマンドとの関連づけを行っています。 ListBoxでは、EventTriggerのEventNameとしては「MouseEnter」、「MouseLeave」、「SelectionChanged」などがあります。
[WPF] コントロールの任意のイベントとコマンド xaml上で関連付けるView
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | < Window x:Class = "LivetWPFApplication100.Views.Window2" xmlns:v = "clr-namespace:LivetWPFApplication100.Views" xmlns:vm = "clr-namespace:LivetWPFApplication100.ViewModels" xmlns:b = "clr-namespace:LivetWPFApplication100.Behaviors" Title = "Window2" Height = "300" Width = "450" WindowStartupLocation = "CenterScreen" > < i:Interaction.Triggers > <!--WindowのContentRenderedイベントのタイミングでViewModelの Initializeメソッドが呼ばれます--> < i:EventTrigger EventName = "ContentRendered" > < l:LivetCallMethodAction MethodTarget = "{Binding}" MethodName = "Initialize" /> </ i:EventTrigger > < i:EventTrigger EventName = "Loaded" > < i:InvokeCommandAction Command = "{Binding Path=Loaded}" CommandParameter="{Binding Mode = OneTime ,RelativeSource= {RelativeSource Mode = FindAncestor ,AncestorType={x:Type Window}}}"/> </ i:EventTrigger > < i:EventTrigger EventName = "Closing" > < i:InvokeCommandAction Command = "{Binding Path=Closing}" CommandParameter="{Binding Mode = OneTime ,RelativeSource= {RelativeSource Mode = FindAncestor ,AncestorType={x:Type Window}}}"/> </ i:EventTrigger > < l:InteractionMessageTrigger MessageKey = "Close" Messenger = "{Binding Messenger}" > < l:WindowInteractionMessageAction /> </ l:InteractionMessageTrigger > </ i:Interaction.Triggers > < i:Interaction.Behaviors > < b:CloseButtonBehavior IsWindowCloseEnable="{Binding ElementName = CloseCheck , Path = IsChecked }"/> </ i:Interaction.Behaviors > < Grid > < Button Command = "{Binding CloseCommand}" Content = "閉じる" Height = "32" HorizontalAlignment = "Left" Margin = "319,217,0,0" Name = "button1" VerticalAlignment = "Top" Width = "97" /> </ Grid > </ Window > |
Window2のViewModelであるViewModel2.csは下記のようになります。
ViewModel
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | using System; // ObservableCollection using System.Collections.Generic; using System.Linq; //INotifyPropertyChanged //PropertyChanged using System.ComponentModel; //参照設定が必要 //using System.Configuration; using Livet; using Livet.Commands; using Livet.Messaging; //CloseCommand using Livet.Messaging.Windows; //ICommand //using System.Windows.Input; using System.Windows; namespace LivetWPFApplication100.ViewModels { class ViewModel2 : ViewModel { public ViewModel2() { var Loaded = new Livet.Commands.ListenerCommand<Window>((w) => { if (NeedHideOwner && w.Owner != null && w.Owner.Visibility == Visibility.Visible) { w.Owner.Hide(); } }); var Closing = new Livet.Commands.ListenerCommand<Window>((w) => { if (NeedHideOwner && w.Owner != null ) { w.Owner.Show(); } }); } public bool NeedHideOwner { get ; set ; } //public ICommand Loaded { get; private set; } //public ICommand Closing { get; private set; } public void Initialize() { XCloseButtonManager.Disable(); } #region CloseCommand private ViewModelCommand _CloseCommand; public ViewModelCommand CloseCommand { get { if (_CloseCommand == null ) { _CloseCommand = new ViewModelCommand(Close); } return _CloseCommand; } } public void Close() { var window = Application.Current.Windows.OfType<Window>(). SingleOrDefault((w) => w.IsActive); window.Close(); } #endregion } } |