依存関係プロパティが無いなら添付プロパティを作ればいいじゃない! ってそんな甘くないか
WPFが面白くってハマリ気味の最近、ちょいとした調べ物の途中で凄い(当社比)裏技を見つけた。
■WPF MVVM Newbie - how should the ViewModel close the form? - Stack Overflow
http://stackoverflow.com/questions/501886/wpf-mvvm-newbie-how-should-the-viewmodel-close-the-form
MVVMパターンでダイアログ閉じるのどうすんのさ?っていうトピックだけども、
DialogResultが依存関係プロパティなら
DialogResult={Binding DialogResult}
で終わりなんだけども、Window.DialogResultプロパティは悲しいかな依存関係プロパティではない。
えーじゃあWindowを継承したクラスわざわざ作るの?って思ってたら添付プロパティという発想があった。
抜粋して、少し整形して書くと
/// <summary> /// WindowのDialogResultプロパティをViewModelから制御するためのクラス /// </summary> public static class DialogResultHelper { /// <summary> /// ViewModelから制御するための依存関係プロパティ /// </summary> public static readonly DependencyProperty DialogResultProperty = DependencyProperty.RegisterAttached( "DialogResult", typeof(bool?), typeof(DialogResultHelper), new PropertyMetadata((d, e) => { var window = d as Window; if (window != null) { //ここ(コールバック)でWindowのDialogResultプロパティを設定(画面が閉じられる) window.DialogResult = e.NewValue as bool?; } })); /// <summary> /// Xamlから添付プロパティとして設定させるためのメソッド /// </summary> public static void SetDialogResult(Window target, bool? value) { target.SetValue(DialogResultProperty, value); } }
を作っておいて、XamlのWindowタグの中に
xmlns:local="clr-namespace:何か" local:DialogResultHelper.DialogResult="{Binding DialogResult}"
って書くと、ViewModelのDialogResultプロパティでWindowのDialogResultプロパティを設定できる。
Coolなアイデアだなと、正直最初は思った。ほかにも応用できそうかなとも。
が、よくよく考えるとOneWayバインドしかできないし、使えるところは限られるかな・・・。
それよか一律にSystem.Windows.Interactivity.EventTriggerとかで設定する方が見た目にもメンテ的にも良いのかもしれない。
(拡張性があるという点も)
(ただし、Blend SDKが必要)
たとえば、Commandでごにょごにょやった後にDialogを閉じたい場合は、
<Window x:Class="WpfApplication7.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:m="clr-namespace:WpfApplication7" xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" x:Name="Window1"> <Window.DataContext> <m:MyViewModel /> </Window.DataContext> <Grid> <Button Content="Button" Margin="100"> <!--トリガのコレクションを設定--> <i:Interaction.Triggers> <i:EventTrigger EventName="Click" > <!--コマンドを実行--> <i:InvokeCommandAction Command="{Binding DoSomethingCommand}" /> <!--WindowのDialogResultを設定する(画面が閉じられる)--> <ei:ChangePropertyAction TargetObject="{Binding ElementName=Window1}" PropertyName="DialogResult" Value="True"/> </i:EventTrigger> </i:Interaction.Triggers> </Button> </Grid> </Window>
って書くのだけど、こっちの方がXamlをぱっと見た目に何をするのかがわかると思う(当社比)
また、「画面を閉じるのはVIEWの責任じゃね?」って観点もあるだろうし。
※ 上記のコードの
上記はあくまで例で、実行順に関する研究はさらに続けます。