102 Views
March 25, 11
スライド概要
MVVM in Silverlight presentation for a SI partner site training in 2010.
FPT ジャパン エグゼクティブエバンジェリスト 独立行政法人 国立印刷局 デジタル統括アドバイザー兼最高情報セキュリティアドバイザー Microsoft で13年間、テクニカルエバンジェリストとして .NET、C#、Visual Studio、Windows、iOS、Android、Microsoft Azure 等の開発者向け技術啓発活動 (DevRel) 。Dell、Accenture、Elastic、VMware 等での DevRel 後、2024年11月1日より現職で DevRel 活動を開始。NVIDIA との戦略的協業 AI GPU クラウド、Azure/AWS/GC 上の AI &データ関連サービスのマーケティング、プリセールス、教育、関連新規サービス開発。元内閣官房 IT 総合戦略室 政府 CIO 補佐官(兼務)、元デジタル庁 ソリューションアーキテクト(兼務)。
- MVVM 及び Prism のご紹介 -
MVVM Model – View – ViewModel 何をするものか どこで使えば一番うまく使えるか 応用 Prism MVVMを有効に使うために ギャップを埋めるために オプション
Silverlight におけるMVVM の重要性 ゴールを達成するためには多くの手段がある 実際に動かしてみよう MVVM イネーブラについて学ぼう Prism 独自のものを作成しよう
MVVM MVC MVP MV???? アプリケーション構築において、メンテナ ンス性やスケーラビリティ確保のために、 一般的に受け入れられているパターン
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
どんなものか?なぜ必要か? 関心の分離 View = UI を担当 Model = 純粋なデータを含む ViewModel = バインディングを通じたView と Model との間のコミュニケーション Silverlight と WPF とで有効活用可能 XAML ベースのデータバインディング テスト可能
どんなものか?なぜ必要か? 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の分離が不明確になる可能性がある)
すべてを一緒に コントロールにデータを表示 UI フレンドリーなエンティ ティや、UI 状態、アクション データを表すエンティティ
MVVM データを表す エンティティ どこから取得したデータかは知る必要なし WCF サービス、WCF RIA Services 等々 バリデーションを含む場合あり
MVVM 画面, UI, Silverlight のUserControl UI のルック&フィールを担当 情報を表示 バインディングを通じて、ViewModel とコ ミュニケート
MVVM MVVM トライアドのためのロジックのメインソー ス Model を View と接続する View を抽象化する View にバインドされたPublic プロパティ INotifyPropertyChanged と、 INotifyCollectionChanged とによる、バイン ディングを通じた View との会話 バインディングを通じたView からの変更の通知 MVVMトライアドの外部とのコミュニケートのた めのサービスの呼び出し
MVVM バリエーション View は ViewModel と何らかの関連性を持 つ 幾つかの実施可能なオプション View First View Model First MVVM トライアドの個々のパーツのメンテ ナンス
MVVM Variations ViewModel は View の XAMLの中のスタ ティックなリソースとして宣言される Expression Blend で作れる もう一つの方法としては、ViewModel を View の分離コードで作成する
DEMO
MVVM バリエーション View は、ViewModelのコンストラク タにインジェクト(=注入)される Example: View がDependency Injection を使って作 成されると、ViewModel が 作成される
MVVM バリエーション View は ViewModel と何らかの形で 一対になる ViewModel と View は一旦作成さ れ、中間段階を経て、その後一対と なる
vm = new MyVM(); view = new MyView(); view.DataContext = vm; // With Unity vm = container.Resolve<IMyVM>(); view = container.Resolve<MyView>(); view.DataContext = vm;
いつでも選択可能 Prism は、オプションのセット 使いたいものだけを選んで使い、残 りは無視して良し 例 : モジュールとコマンドは選ぶが、イベント アグリゲーションとリージョンは無視する Prism: patterns & practices Composite Application Guidance for WPF and Silverlight site http://www.codeplex.com/CompositeWPF
スタートするための機能 アプリケーションを起動 メイン UI コンテナをスタート (Shell) (必要に応じて)モジュールの登録とロード グローバルシングルトンの登録 (オプション) 通常 “Bootstrapper プロジェクト” に含まれ る
メインView メイン UI コンテナ ロードされ得るすべての Viewをホスト リージョンに分割可能 Shell 自身は、その中に何がロードされる かを知らない
Content エリア View を配置できる Shell の中のエリア 名前を付ける必要あり コンテキストを内包可能 (オプション) RegionManager により Region をメンテナ ンス可能
Self Contained Modules ユーザーにとってはシームレス 分割して開発される 他のモジュールを参照してはならない Solution は Modules に分割される Example: City government application Module 1: Managing land parcels Module 2: Traffic light administration Module 4: City Parks Modules は、infrastructure と Models をシェアする
Unityの利用 Unity 又は他の DI ツール群 ( 例:Ninject) テスト可能でモック作成 抽象化 コンテナオブジェクトにより、クラスがそ のインターフェースに従って登録される インターフェースをリクエストされたと き、コンテナは、当該インターフェースと 一緒に登録されたクラスを、作成する シングルトンのサポート
container.RegisterType <IMyViewModel, MyViewModel>();
container.Resolve<IMyViewModel>();
共通のTools Silverlight クラスライブラリプロジェク ト モジュールのために共有可能なアイテムを 含む Classes Assets Resources 何の参照も作成しない 純粋なライブラリ
アクションとリアクション データバインディングを通じた View と ViewModel との間のイベントを許可 ViewModel が宣言するのは Command receiver Command は XAML の中で宣言される Button - Click ListBox (Selector) – Selected Command は、 ViewModel の Command receiver にデータバインドされる ルールベースで disabled/enabled 設定可能
Silverlight 4 プロジェクトにおける ICommand 実装は、数ステップで足りる 問い合わせの多い個所なので、下記に Commanding 実装のためのシンプルなテク ニックを記述する
最初のステップは、ICommand インターフェース クラスの実装 このクラスはCommanding アスペクトを管理する 他にも色々オプションがあるところ、ここではシンプ ルなICommand の実装方法を紹介 当該 DelegatedCommand クラスで実装するの は、ICommand の CanExecute メソッド、 Execute メソッド、そして、 CaneExecuteChanged イベント このコードはそのままコピー&ペーストして利用 可能
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;
}
…
#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; }
・・・続き・・・ public event EventHandler CanExecuteChanged; public void Execute(object parameter) { executeAction(parameter); } #endregion }
//ICommand を表示するための Public プロパティ を ViewModel に追加 //このプロパティは 、通常は、ボタン等により、 View にバインドされる public ICommand LoadProductsCommand { get; set; }
//ViewModel のコンストラクタの中で、 1で作成したコマンドプロパティを設定する LoadProductsCommand = new DelegateCommand (LoadProducts, CanLoadProducts);
// ViewModel が View からアクセス可能なこと を確認する // 様々な方法があるところ、シンプルに View の XAML 中の Static Resource として作成 <UserControl.Resources> <local:ProductViewModel x:Key="vm"/> </UserControl.Resources>
//ボタンコントロールを追加し、当該コマンドプロパティを ViewModel の中で作ったコマンドにバインドする //当該Command に parameter を渡したい場合には、 CommandParameter プロパティを、当該 View の中の要素にバインド できる (通常は parameter は必要ないが、例として実装) <Button Content="Load" Width="120" Command="{Binding LoadProductsCommand}" CommandParameter= "{Binding ElementName= FilterTextBox, Path=Text}" />
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.AllProducts
where 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");
}
}
}
public 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)); } }
パブリッシャとサブスクライバ 色々な種類のイベントをパブリッシュ及び サブスクライブ可能にする クロスモジュール化可能 サブスクライバによるフィルタリング可能 例えば: 1. Shell の中のMenu アイテム上をクリック 2. イベントはパブリッシャから呼び出される 3. イベントはサブスクライバに受信される 4. それにより、当該サブスクライバは、 Shell の中の、ある Region の中の、一つ のViewをロードする
共通のTools Infrastructure は、Silverlight class library プロジェクト クラス、アセット、リソースを含み、モ ジュール間で共有される 他のモジュールを参照してはならない Web サービスをコールしてはならない 純粋なライブラリ
DEMO
Screensを生成する スクリーン間をナビゲート可能にしなけれ ばならない View 同志はお互いのことを知らない 独自の Screen Conductor を作成可能 Loading / Unloading Displaying / Hiding そのまま終了して良いですか? 自分でクリーンアップしましょう!
Key Players Screen MVVM トライアドを管理 ScreenFactory Screen class を作成 ScreenFactoryRegistry ScreenFactory ディレクトリ ScreenConductor Screen のアクティベーションイベントをリッス ンしたり、その上で動いたりする ScreenCollection Screens を収集する
DEMO
Blog、チュートリアル、サンプル、等々 Introducing the Earthquake Locator – A Bing Maps Silverlight Application, part 1 http://geekswithblogs.net/bdiaz/archive/2010/03/06/introducingthe-earthquake-locator--a-bing-maps-silverlight-application.aspx MVVM Light Toolkit http://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-appsexample-for-silverlight-3-rtm-and-net-ria-services-july-updateviewmodel.aspx ViewModel Pattern in Silverlight using Behaviors http://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.