Post on 28-May-2015
description
Silverlight を使ったLarge-Scale Application の構築- MVVM 及び Prism のご紹介 -
鈴木 章太郎アーキテクトエバンジェリストマイクロソフト株式会社http://blogs.msdn.com/shosuz/ Twitter : @shosuz
アウトライン
MVVMModel – View – ViewModel何をするものかどこで使えば一番うまく使えるか応用
PrismMVVM を有効に使うためにギャップを埋めるためにオプション
ゴール
Silverlight における MVVM の重要性ゴールを達成するためには多くの手段がある
実際に動かしてみよう
MVVM イネーブラについて学ぼうPrism独自のものを作成しよう
他にも MV_ とついているものが… ?
MVVMMVCMVPMV????
アプリケーション構築において、メンテナンス性やスケーラビリティ確保のために、一般的に受け入れられているパターン
Model-View-ViewModel 全体像MVVM, Prism, MEF - WCF RIA Services 連携
WPF 、 Silverlight の疎結合 ソリューションのパターン下記の実装を行う ( トライアド )
Model Data(Web)Service のエンティティ( をラップする )WCF RIA Services を Model と することも可能
ViewModel Model を UI に合わせて公開する
View ViewModel を XAML 等でバインドする
参照: http://msdn.microsoft.com/ja-jp/magazine/dd458800.aspx
MVVMどんなものか?なぜ必要か?
関心の分離View = UI を担当Model = 純粋なデータを含むViewModel = バインディングを通じたView と Model との間のコミュニケーションSilverlight と WPF とで有効活用可能
XAML ベースのデータバインディングテスト可能
MVVMどんなものか?なぜ必要か?
Model : INotifyPropertyChanged 、 IDataErrorInfo を実装しているクラス (UI 要素は持たず、 Setter/Getter としてのプロパティを持つのみ )
ViewModel が取り扱うデータを保持するものViewModel : INotifyPropertyChanged を実装しているクラス (UI 要素は持たず、ビジネスロジックやサーバーとの通信を担当する )
多くは ObservableCollection として View にバインドするデータ(Model) を取得し、保持するもの分離コードで Command とイベントハンドラ (Command Receiver) の対応付けを行うExpression Blend のオブジェクトデータソースとしてスタティックリソース宣言が可能(ドラッグ&ドロップで UI 構築)
View :XAML による UserControl (UI 要素のみ )ViewModel から提供されるデータ (Model) を 2-ways データバインドにより表示・更新するXAML 側で Command の宣言を行うできれば分離コードを一切もたない dumb コントロールとしての実装が望ましい (ViewModel の割り当てを View の分離コードで実行することもできるが、 View – ViewModel の分離が不明確になる可能性がある )
The MVVM のトライアドすべてを一緒に
コントロールにデータを表示
UI フレンドリーなエンティティや、 UI 状態、アクション
データを表すエンティティ
ViewModel
View
Model
ModelMVVM
データを表すエンティティどこから取得したデータかは知る必要なし
WCF サービス、 WCF RIA Services 等々バリデーションを含む場合あり
ViewMVVM
画面 , UI, Silverlight の UserControl UI のルック & フィールを担当情報を表示バインディングを通じて、 ViewModel とコミュニケート
ViewModelMVVM
MVVM トライアドのためのロジックのメインソースModel を View と接続するView を抽象化するView にバインドされた Public プロパティINotifyPropertyChanged と、 INotifyCollectionChanged とによる、バインディングを通じた View との会話バインディングを通じた View からの変更の通知 MVVM トライアドの外部とのコミュニケートのためのサービスの呼び出し
MVVM はどこから始めるのが良いか ?MVVM バリエーション
View は ViewModel と何らかの関連性を持つ幾つかの実施可能なオプション
View FirstView Model First
MVVM トライアドの個々のパーツのメンテナンス
View First MVVM Variations
ViewModel は View の XAML の中のスタティックなリソースとして宣言される
Expression Blend で作れる
もう一つの方法としては、 ViewModel を View の分離コードで作成する
DEMO
View First MVVM
demo
ViewModel FirstMVVM バリエーション
View は、 ViewModel のコンストラクタにインジェクト ( =注入 ) される
Example:View が Dependency Injection を使って作成されると、 ViewModel が 作成される
View と ViewModel との結び付けMVVM バリエーション
View は ViewModel と何らかの形で一対になるViewModel と View は一旦作成され、中間段階を経て、その後一対となる
View と ViewModel との結び付け
vm = new MyVM();view = new MyView();view.DataContext = vm;
// With Unityvm = container.Resolve<IMyVM>();view = container.Resolve<MyView>();
view.DataContext = vm;
Prism についていつでも選択可能
Prism は、オプションのセット使いたいものだけを選んで使い、残りは無視して良し
例 : モジュールとコマンドは選ぶが、イベントアグリゲーションとリージョンは無視する
Prism: patterns & practices Composite Application Guidance for WPF and Silverlight site
http://www.codeplex.com/CompositeWPF
Prism の技術コンセプト
Container
Commands
Bootstrapper
Regions
Modules
Event Aggregation
Unity and DI
Shell
Bootstrapperスタートするための機能
アプリケーションを起動メイン UI コンテナをスタート (Shell)(必要に応じて)モジュールの登録とロードグローバルシングルトンの登録 ( オプション )通常 “ Bootstrapper プロジェクト” に含まれる
Shellメイン View
メイン UI コンテナロードされ得るすべての View をホストリージョンに分割可能Shell 自身は、その中に何がロードされるかを知らない
RegionsContent エリア
View を配置できる Shell の中のエリア名前を付ける必要ありコンテキストを内包可能 ( オプション )RegionManager により Region をメンテナンス可能
ModularitySelf Contained Modules
ユーザーにとってはシームレス分割して開発される他のモジュールを参照してはならないSolution は Modules に分割されるExample:
City government applicationModule 1: Managing land parcelsModule 2: Traffic light administrationModule 4: City Parks
Modules は、 infrastructure と Models をシェアする
Dependency InjectionUnity の利用
Unity 又は他の DI ツール群 ( 例 :Ninject)テスト可能でモック作成抽象化コンテナオブジェクトにより、クラスがそのインターフェースに従って登録されるインターフェースをリクエストされたとき、コンテナは、当該インターフェースと一緒に登録されたクラスを、作成するシングルトンのサポート
クラスへのインターフェースの登録
container.RegisterType<IMyViewModel,
MyViewModel>();
コンクリート Class の作成
container.Resolve<IMyViewModel>();
Infrastructure共通の Tools
Silverlight クラスライブラリプロジェクトモジュールのために共有可能なアイテムを含む
ClassesAssetsResources
何の参照も作成しない純粋なライブラリ
Commandingアクションとリアクション
データバインディングを通じた View と ViewModel との間のイベントを許可ViewModel が宣言するのは Command receiverCommand は XAML の中で宣言される
Button - ClickListBox (Selector) – Selected
Command は、 ViewModel の Command receiver にデータバインドされるルールベースで disabled/enabled 設定可能
Commanding 実装のための5 つのステップ – 前提
Silverlight 4 プロジェクトにおける ICommand 実装は、数ステップで足りる問い合わせの多い個所なので、下記にCommanding 実装のためのシンプルなテクニックを記述する
Commanding 実装のための 5つのステップ – ICommand の実装最初のステップは、 ICommand インターフェースクラスの実装
このクラスは Commanding アスペクトを管理する他にも色々オプションがあるところ、ここではシンプルな ICommand の実装方法を紹介
当該 DelegatedCommand クラスで実装するのは、 ICommand の CanExecute メソッド、Execute メソッド、そして、 CaneExecuteChanged イベントこのコードはそのままコピー &ペーストして利用可能
Commanding 実装のための 5 つのステップ – ICommand の実装 ① public class DelegateCommand : ICommand { Func<object, bool> canExecute; Action<object> executeAction; bool canExecuteCache; public DelegateCommand(Action<object> executeAction, Func<object, bool>canExecute) {
this.executeAction = executeAction; this.canExecute = canExecute; } …
Commanding 実装のための 5 つのステップ – ICommand の実装 ②#region ICommand Members
public bool CanExecute(object parameter) { bool temp = canExecute(parameter); if (canExecuteCache != temp) { canExecuteCache = temp; if (CanExecuteChanged != null) { CanExecuteChanged(this, new
EventArgs()); } } return canExecuteCache; }
Commanding 実装のための 5 つのステップ – ICommand の実装 ②
・・・続き・・・public event EventHandler
CanExecuteChanged; public void Execute(object parameter) { executeAction(parameter); }#endregion}
Commanding 実装のための 5 つのステップ – Command の定義
//ICommand を表示するための Public プロパティ を ViewModel に追加// このプロパティは 、通常は、ボタン等により、 View にバインドされる
public ICommand LoadProductsCommand { get;
set; }
Commanding 実装のための 5 つのステップ – Command の作成
//ViewModel のコンストラクタの中で、 1 で作成したコマンドプロパティを設定する
LoadProductsCommand = new DelegateCommand
(LoadProducts, CanLoadProducts);
Commanding 実装のための 5 つのステップ – ViewModel の作成// ViewModel が View からアクセス可能なこと を確認する// 様々な方法があるところ、シンプルに View
の XAML 中の Static Resource として作成
<UserControl.Resources> <local:ProductViewModel
x:Key="vm"/></UserControl.Resources>
Commanding 実装のための 5 つのステップ – Command のバインド//ボタンコントロールを追加し、当該コマンドプロパティを ViewModel の中で作ったコマンドにバインドする// 当該 Command に parameter を渡したい場合には、 CommandParameter プロパティを、当該 View の中の要素にバインド できる ( 通常は parameter は必要ないが、例として実装 )
<Button Content="Load" Width="120" Command="{Binding
LoadProductsCommand}" CommandParameter= "{Binding ElementName=
FilterTextBox, Path=Text}" />
Commanding 実装のための 5 つのステップ – ProductViewModel 完成品 public class ProductViewModel : ViewModelBase
{ public ProductViewModel(){
this.Products = new ObservableCollection<Product>(); this.AllProducts = new ObservableCollection<Product>();this.AllProducts.Add(new Product { ProductId = 1, ProductName = "Apple" });
this.AllProducts.Add(new Product { ProductId = 2, ProductName = "Orange" });this.AllProducts.Add(new Product { ProductId = 3, ProductName = "Banana" }); this.AllProducts.Add(new Product { ProductId = 4, ProductName = "Pear" })this.AllProducts.Add(new Product { ProductId = 5, ProductName = "Grape" }); this.AllProducts.Add(new Product { ProductId = 6, ProductName = "Grapefruit" });this.AllProducts.Add(new Product { ProductId = 7, ProductName = "Strawberry" })this.AllProducts.Add(new Product { ProductId = 8, ProductName = "Melon" });this.AllProducts.Add(new Product { ProductId = 9, ProductName = "Guava" });this.AllProducts.Add(new Product { ProductId = 10, ProductName = "Kiwi" });this.AllProducts.Add(new Product { ProductId = 11, ProductName = "Pineapple" });this.AllProducts.Add(new Product { ProductId = 12, ProductName = "Mango" });
LoadProductsCommand = new DelegateCommand(LoadProducts, CanLoadProducts); } private void LoadProducts(object param) {
string filter = param as string ?? string.Empty; this.Products.Clear();var query = from p in this.AllProductswhere p.ProductName.ToLower().StartsWith(filter.ToLower())select p;foreach (var item in query) {
this.Products.Add(item);}
} private bool CanLoadProducts(object param) { return true } public ICommand LoadProductsCommand { get; set; } public ObservableCollection<Product> AllProducts { get; set; } private ObservableCollection<Product> products; public ObservableCollection<Product> Products {
get{
return products}set{ products = value;
this.FirePropertyChanged("Product");}
} }
Commanding 実装のための 5 つのステップ – ViewModel Basepublic abstract class ViewModelBase : INotifyPropertyChanged{
public ViewModelBase(){}
public event PropertyChangedEventHandler PropertyChanged;
protected void FirePropertyChanged(string propertyname) {
var handler = PropertyChanged; if (handler != null)
handler (this, new
PropertyChangedEventArgs(propertyname));}
}
Event Aggregatorパブリッシャとサブスクライバ
色々な種類のイベントをパブリッシュ及びサブスクライブ可能にするクロスモジュール化可能サブスクライバによるフィルタリング可能例えば :
1. Shell の中の Menu アイテム上をクリック2. イベントはパブリッシャから呼び出される3. イベントはサブスクライバに受信される4. それにより、当該サブスクライバは、
Shell の中の、ある Region の中の、一つの View をロードする
Infrastructure共通の Tools
Infrastructure は、 Silverlight class library プロジェクトクラス、アセット、リソースを含み、モジュール間で共有される他のモジュールを参照してはならないWeb サービスをコールしてはならない純粋なライブラリ
DEMO
Modular MVVM and Prism
demo
Screen Presentation EnablerScreens を生成する
スクリーン間をナビゲート可能にしなければならないView 同志はお互いのことを知らない独自の Screen Conductor を作成可能
Loading / UnloadingDisplaying / Hidingそのまま終了して良いですか ?自分でクリーンアップしましょう !
Screen Presentation FrameworkKey Players
ScreenMVVM トライアドを管理
ScreenFactoryScreen class を作成
ScreenFactoryRegistryScreenFactory ディレクトリ
ScreenConductorScreen のアクティベーションイベントをリッスンしたり、その上で動いたりする
ScreenCollectionScreens を収集する
DEMO
Screen Conductor
demo
参考情報その他Blog 、チュートリアル、サンプル、等々
Introducing the Earthquake Locator – A Bing Maps Silverlight Application, part 1
http://geekswithblogs.net/bdiaz/archive/2010/03/06/introducing-the-earthquake-locator--a-bing-maps-silverlight-application.aspx
MVVM Light Toolkithttp://www.galasoft.ch/mvvm/getstarted/
Business Apps Example for Silverlight 3 RTM and .NET RIA Services July Update: Part 25: ViewModel
http://blogs.msdn.com/brada/archive/2009/09/07/business-apps-example-for-silverlight-3-rtm-and-net-ria-services-july-update-viewmodel.aspx
ViewModel Pattern in Silverlight using Behaviorshttp://www.nikhilk.net/Silverlight-ViewModel-Pattern.aspx
Simple Step for Commanding in Silverlight http://devlicio.us/blogs/christopher_bennage/archive/2010/03/03/1-simple-step-for-commanding-in-silverlight.aspx
© 2010 Microsoft Corporation. All rights reserved. Microsoft, Windows, Windows Vista and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries.The information herein is for informational purposes only and represents the current view of Microsoft Corporation as of the date of this presentation. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information provided after the date of this presentation. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.