マスターコンテンツとViewModelクラスの連携

マスターコンテンツを実装したので、前に作ったWindow用VMと連携するために、マスターコンテンツ(TawamureContents)側にも働いてもらう事にした。
対Window用ViewModelをとりあえず作るか。
対Window用ViewModelをとりあえず作るか。(続き)
MVVMで、メッセージボックスを表示する(壱)。
MVVMで、メッセージボックスを表示する(弐)
MVVMで、メッセージボックスを表示する(参)
で実装したBaseWindowVMクラスのメッセージコマンド系プロパティとバインディングさせる。
まずは起動、終了系のコマンドと連携させるために、マスターコンテンツのコンストラクタに実装を加える。
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
...
/// <summary>
/// コンストラクタ
/// </summary>
public TawamureContents() {
BindingOperations.SetBinding(
this,
FrameworkElementBehavior.OnLoadedCommandProperty,
new Binding("LoadedCommand"){Mode = BindingMode.OneWay});
BindingOperations.SetBinding(
this,
FrameworkElementBehavior.UnloadedCommandProperty,
new Binding("UnloadedCommand"){Mode = BindingMode.OneWay});
BindingOperations.SetBinding(
this,
WindowBehavior.ClosingCommandProperty,
new Binding("ClosingCommand"){Mode = BindingMode.OneWay});
return;
}
これは、XAMLで↓のように書くのと同義となる。
<Window x:Class="TawamureDays.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:tw="http://schemas.tawamuredays.jp/wpf/gui"
Title="MainWindow" Height="350" Width="525"
tw:FrameworkElementBehavior.OnLoadedCommand="{Binding LoadedCommand}"
tw:FrameworkElementBehavior.UnloadedCommand="{Binding UnloadedCommand}"
tw:WindowBehavior.ClosingCommand="{Binding ClosingCommand}
">
<tw:TawamureContents>

</tw:TawamureContents>
</Window>
XAMLに書くもが良いのかもしれないけど、そうすると、すべての画面において記述が必要となる。BaseWindowVMクラスを基底にすれば、それだけでプロパティ名は固定されるので、一々書くのは手間となる。なので、コードによるバインディングを仕事では行なっている。実装するのは、共通系の開発者だけになり、各画面の開発担当者が個別に実装する必要がない。それだけで、多少効率はあがる(説明する手間, 理解する手間、実際に実装する手間が減る)。
更にメッセージボックス系の添付プロパティをつける。これも同様にコード上でバインディングさせる。ただし、添付プロパティの対象をWindowクラスにしているので、ワンクッション置くことになる。
/// <summary>
/// コンストラクタ
/// </summary>
public TawamureContents() {
(中略)
this.Loaded += new RoutedEventHandler(TawamureContents_Loaded);
return;
}

/// <summary>
/// Loadedイベントハンドラ
/// </summary>
/// <param name="sender">イベント発生元</param>
/// <param name="e">イベント引数</param>
private void TawamureContents_Loaded(object sender, RoutedEventArgs e) {
var window = Window.GetWindow(this);

if (window != null) {
WindowBehavior.SetUseMessageCommand(window, true);
}
return;
}

次に、SetUseMessageCommandメソッドの中身をちょっと改修する。
このメソッドは、DataContextChangedイベントが発生したら、処理をするという実装になっているけど、
既にDataContextが設定されていた時の事が考慮に入っていなかった。
プロパティ値変更イベント用メソッドを以下のようにした。
/// <summary>
/// UseMessageCommandプロパティ値変更イベントハンドラ
/// </summary>
/// <param name="dpObj">変更発生元</param>
/// <param name="e">イベント引数</param>
private static void OnUseMessageCommandPropertyChanged(
DependencyObject dpObj, DependencyPropertyChangedEventArgs e) {

var window = dpObj as Window;

if (window != null && (bool)e.NewValue) {
window.DataContextChanged +=
new DependencyPropertyChangedEventHandler(Window_DataContextChanged);
window.Closed += new System.EventHandler(Window_Closed);
}


//ここを追加
if (window.DataContext != null) {
Window_DataContextChanged(window,
new DependencyPropertyChangedEventArgs(
Window.DataContextProperty,
null, window.DataContext));
}

return;
}
これで設定済でも動くようになる。
ViewModelクラス実装時に、BaseWindowVMを継承させ、DataContextに設定すれば良いだけとなる。
○XAML側の実装
<Window x:Class="TawamureDays.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:tw="http://schemas.tawamuredays.jp/wpf/gui"
Title="MainWindow" Height="350" Width="525"">
<tw:TawamureContents>

</tw:TawamureContents>
</Window>

○コードビハインド
/// <summary>
/// MainWindow.xaml の相互作用ロジック
/// </summary>
public partial class MainWindow : Window {

public MainWindow() {
InitializeComponent();
this.DataContext = new TawamureVM();
}
}

○DataContext(ViewModel)側の実装
/// <summary>
/// ViewModelクラス
/// </summary>
public class TawamureVM : BaseWindowVM {

/// <summary>
/// Loaded時に呼び出されるコマンドの実行メソッド。<br/>
/// 初期化処理等、Loaded時に必要な実装をここで行います。<br/>
/// </summary>
/// <param name="parameter">パラメータ</param>
protected override void OnLoaded(object parameter) {
base.OnLoaded(parameter);

this.ShowInfoMessage("INFO MESSAGE!");
this.ShowWarnMessage("WARNING MESSAGE!");
this.ShowErrorMessage("ERROR MESSAGE!");

return;
}
}

ここまでで、ViewModel側で、
○Load時の実装、Closing時の実装を行う。
○メッセージボックスを使う。
が可能になった。次は。
○VM側から画面終了を要求する
○マウスカーソルの形を変える要求をVM側から行う
を実装しようかな。

(2012/09/11追記)
XAMLで設定した場合、呼び出される順序が変わるようで、上手くメッセージが表示できない現象を確認してしまった。なので、以下のように変更した。
    /// <summary>
/// コンストラクタ
/// </summary>
public TawamureContents() {
//...
this.Initialized += new EventHandler(TawamureContents_Initialized);
return;
}

/// <summary>
/// 初期化後イベントハンドラ
/// </summary>
/// <param name="sender">イベント発生元</param>
/// <param name="e">イベント引数</param>
private void TawamureContents_Initialized(object sender, EventArgs e) {
var window = Window.GetWindow(this);

if (window != null) {
WindowBehavior.SetUseMessageCommand(window, true);
window.Closed += new EventHandler(Window_Closed);
} else {
this.Loaded += new RoutedEventHandler(TawamureContents_Loaded);
}
}

/// <summary>
/// Loadedイベントハンドラ
/// </summary>
/// <param name="sender">イベント発生元</param>
/// <param name="e">イベント引数</param>
private void TawamureContents_Loaded(object sender, RoutedEventArgs e) {
var window = Window.GetWindow(this);

if (window != null) {
WindowBehavior.SetUseMessageCommand(window, true);
window.Closed += new EventHandler(Window_Closed);
}
return;
}
InitializedでWindowの実体を確保できれば、その時点で行うようにしてある。
スポンサーサイト
当サイトは基本をすっ飛ばしてます。基本文法等は、@ITをどうぞ
カテゴリー: WPF4 | コメント: 0 | トラックバック: 0


この記事へのコメント

コメントの投稿

非公開コメント


サイドバー背後固定表示サンプル

当ブログに書かれたソースコードは流用自由です。

バグ、スペルミス等はありうる事です。

ご利用の際は自己責任でお願いしますm(_ _)m