#WPFでMVVMは難しい
残念なことに、WPFでMVVMパターンを適用する際には、.NET標準だけ使うとなると、綺麗でわかりやすく保守が容易なコードが書けません。
書けないような基盤しかないのです。
なので、PrismなどのMVVM基盤ライブラリが必要となります。
https://msdn.microsoft.com/ja-jp/library/gg406140.aspx
他にも様々なライブラリが公開されていますが、MS謹製ということで今回はPrismを利用しようと思います。
Prismを利用することで得られるメリットを公開します。
以下の予定です。
- BindableBase/DelegateCommand ~ViewModelの基盤~
- ErrorsContaier ~便利なエラー通知~
- ViewModelLocationProvider ~ViewとViewModelを自動で関連付け~
- Regionってなんなのさ ~Viewの配置をお手軽に~
- IModuleとUnity ~UIでDI~
- DIPパターンの恩恵 ~MSBuildで並列ビルド~
本稿は上記3の記事になります。
※Visual Studio 2013 Community Editionで実験しています。
#ViewModelLocationProvider
これまでやってきたサンプルでは、ViewとViewModelの紐付けは以下のようになっています。
using Microsoft.Practices.Prism.Mvvm;
using System.Windows;
namespace KStore.Calc._2
{
public partial class CalcView : Window
{
public CalcView()
{
InitializeComponent();
this.DataContext = new CalcViewModel(); // <-- ここで紐づけ
}
}
}
この
this .DataContext = new CalcViewModel();
を自動でやってくれるというちょっとオーバースペックな機能がPrismにはあります。
いや、オーバースペックではなく、今後必要になるのですが、まだあまり必要性は感じられません。
とにかく、やってみます。
CalcView.xamlに以下の2行を追加します。
<Window x :Class="KStore.Calc._2.CalcView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x ="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d ="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc ="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local ="clr-namespace:KStore.Calc._2"
mc:Ignorable ="d"
Title="Calc" Height ="350" Width="525"
xmlns:prism="clr-namespace:Microsoft.Practices.Prism.Mvvm;assembly=Microsoft.Practices.Prism.Mvvm.Desktop"
prism:ViewModelLocator.AutoWireViewModel ="True"
>
</Window>
このままビルドすると、ビルドは通りますが、以下のように怒られます。
Your views must implement IView
言われたとおりに、CalcViewにIViewを実装。これはほとんどマーカーインタフェースですね。
DataContextにViewModelを紐付けする行も削除しました。
using Microsoft.Practices.Prism.Mvvm;
using System.Windows;
namespace KStore.Calc._3
{
public partial class CalcView : Window, IView // <-- このインターフェースを追加
{
public CalcView()
{
InitializeComponent();
}
}
}
バインドされていない。。。
何故か。
ViewModelLocationProviderのコードを見ると、
Viewの名前に加えて、"ViewModel"が必要みたいです。
今は、
CalcView -> CalcViewModelにしていたのですが、
CalcView -> CalcViewViewModel でないとダメみたいです。
うーん。Viewの名前は末尾に"View"にしないほうが良さそうですね。
気を取り直して、CalcViewViewModel にしてみて、実行します。
バインドされました!
これを使うには、ViewModelの命名規則を必ず
Viewの名前 + "ViewModel"とする必要があります。
上記はXAMLのみで完結する記載でしたが、XAMLで記載せず、コードビハインドで以下のように書いてもOKです。
using Microsoft.Practices.Prism.Mvvm;
using System.Windows;
namespace KStore.Calc._3
{
public partial class CalcView : Window, IView
{
public CalcView()
{
InitializeComponent();
ViewModelLocationProvider.AutoWireViewModelChanged(this);
}
}
}
今回はあまり長くならずに済みました。
#まとめ
ViewModelLocationProviderを使うには、Viewの名前とViewModelの名前に規則性を持たせる必要があります。
Viewの名前に "ViewModel"を末尾に加えます。
例:
CalcView -> CalcViewViewModel
Viewの名前は末尾に"View"をつけないほうが良さそう。