2009-05-12 20 views
18

this questionの助けを借りて、モデルの変更をリアルタイムでXAML(現在の日付/時刻)に表示する、以下のMVVM構造をまとめました。脂肪モデル、スキニーViewModelsとダムビュー、最高のMVVMのアプローチ?

は、このクールな利点は、あなたが デザインモードVisual Studioまたは ブレンドの、であなたのビューを見たとき、あなたがそのでの意味時間によって刻々と過ぎ、 を参照してくださいということまで で設定しましたデザインタイムは モデルのライブデータにアクセスできます。仕事にこれを取得する過程で

、私はINotifyPropertyChangeの実施を含め、私のモデルに私のViewModelからバルク移動、のほとんどを見て驚きました。もう1つの変更点は、が、ViewModelではのプロパティにバインドされなくなりましたが、のメソッドにバインドされなくなりました。

だから、現在、これはMVVMの私の好きな味です:

  1. ビューはダムです:それぞれの

    • 1たObjectDataProviderを使用すると、メソッドにモデル
    • から各たObjectDataProviderマップを必要とするオブジェクト(プロパティではなく)ViewModelで
    • x:XAML要素の名前プロパティ
  2. ViewModelにはスキニーです:

    • モデル:

      • あなたのViewModelで唯一のものはあなたのビューが
    • モデルが太っているバインドにメソッドですそれぞれのプロパティでINotifyPropertyChangedを実装しています。

    • ViewModelのすべてのメソッド(GetCurrentCustomerなど)には、対応するシングルトンメソッド(例:GetCurrentCustomer)があります。
    • モデルは

質問この例のような機能をスレッディング任意のリアルタイムの面倒を見る:

  1. 実際のシナリオでMVVMを実施しているあなたの人々は、これです基本的な構造も決まりました。もしそうでなければ、どのように変化しますか?
  2. これを拡張して、ルーティングされたコマンドとルーティングされたイベントを含めるにはどうすればよいでしょうか?

次のコードは、XAMLとコードを新しいWPFプロジェクトにコピーするだけで動作します。

XAML:背後に

<Window x:Class="TestBinding99382.Window1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="clr-namespace:TestBinding99382" 
    Title="Window1" Height="300" Width="300"> 

    <Window.Resources> 
     <ObjectDataProvider 
      x:Key="DataSourceCustomer" 
      ObjectType="{x:Type local:ShowCustomerViewModel}" 
         MethodName="GetCurrentCustomer"/> 
    </Window.Resources> 

    <DockPanel DataContext="{StaticResource DataSourceCustomer}"> 
     <StackPanel DockPanel.Dock="Top" Orientation="Horizontal"> 
      <TextBlock Text="{Binding Path=FirstName}"/> 
      <TextBlock Text=" "/> 
      <TextBlock Text="{Binding Path=LastName}"/> 
     </StackPanel> 
     <StackPanel DockPanel.Dock="Top" Orientation="Horizontal"> 
      <TextBlock Text="{Binding Path=TimeOfMostRecentActivity}"/> 
     </StackPanel> 

    </DockPanel> 
</Window> 

コード:

using System.Windows; 
using System.ComponentModel; 
using System; 
using System.Threading; 

namespace TestBinding99382 
{ 
    public partial class Window1 : Window 
    { 
     public Window1() 
     { 
      InitializeComponent(); 
     } 
    } 

    //view model 
    public class ShowCustomerViewModel 
    { 
     public Customer GetCurrentCustomer() { 
      return Customer.GetCurrentCustomer(); 
     } 
    } 

    //model 
    public class Customer : INotifyPropertyChanged 
    { 
     private string _firstName; 
     private string _lastName; 
     private DateTime _timeOfMostRecentActivity; 
     private static Customer _currentCustomer; 
     private Timer _timer; 

     public string FirstName 
     { 
      get 
      { 
       return _firstName; 
      } 
      set 
      { 
       _firstName = value; 
       this.RaisePropertyChanged("FirstName"); 
      } 
     } 

     public string LastName 
     { 
      get 
      { 
       return _lastName; 
      } 
      set 
      { 
       _lastName = value; 
       this.RaisePropertyChanged("LastName"); 
      } 
     } 

     public DateTime TimeOfMostRecentActivity 
     { 
      get 
      { 
       return _timeOfMostRecentActivity; 
      } 
      set 
      { 
       _timeOfMostRecentActivity = value; 
       this.RaisePropertyChanged("TimeOfMostRecentActivity"); 
      } 
     } 

     public Customer() 
     { 
      _timer = new Timer(UpdateDateTime, null, 0, 1000); 
     } 

     private void UpdateDateTime(object state) 
     { 
      TimeOfMostRecentActivity = DateTime.Now; 
     } 

     public static Customer GetCurrentCustomer() 
     { 
      if (_currentCustomer == null) 
      { 
       _currentCustomer = new Customer 
        { FirstName = "Jim" 
         , LastName = "Smith" 
         , TimeOfMostRecentActivity = DateTime.Now 
        }; 
      } 
      return _currentCustomer; 
     } 

     //INotifyPropertyChanged implementation 
     public event PropertyChangedEventHandler PropertyChanged; 
     private void RaisePropertyChanged(string property) 
     { 
      if (PropertyChanged != null) 
      { 
       PropertyChanged(this, new PropertyChangedEventArgs(property)); 
      } 
     } 
    } 
} 
+0

、あなたはこれらの答えを見ていたいかもしれません:http://stackoverflow.com/questions/650010/mvvm-routed-and-relay-command/6441472#6441472を – Marc

答えて

28

はここで何が価値があるために、私の意見です:

私は本当にアプローチに同意しませんあなたはお勧めします(ダムビューを除く)。現実の生活では、しばしば既存のモデルを使用する必要があります。変更する時間がない既存のコードや、コードを持たないライブラリなどです。私の意見では、モデルは表示方法を完全に知らなくてはならず、WPF以外のアプリケーションでも簡単に使用できるはずです。したがって、INotifyPropertyChangedというINotifyCollectionChangedのような特定のインターフェイスを実装してMVVMで使用できるようにする必要はありません。私はUIに関連するすべてのロジックがViewModelにあるべきだと思う。

RoutedEventsRoutedCommandsについては、MVVMパターンでの使用にはあまり適していません。私は通常、RoutedEventsをできるだけ使用しないようにし、全くRoutedCommandsを使用しないようにしています。代わりに、私のViewModelsはRelayCommandの詳細についてはthis articleをJosh Smithが参照してください)をUIにバインドするRelayCommandのプロパティを公開します。私は実際にいくつかのコントロールのイベントを処理する必要があるとき、私はViewModelににイベントをマップするために添付ビヘイビアを使用すること(Marlon Grech's implementationを見て)コマンド

ので、要約で:

  • ダムビュー
  • ビッグスマートのViewModel
  • したいか、もちろん

を使用する必要が任意のモデルは、それはちょうど私のアプローチだし、それが最高ではないかもしれないが、私はそれで非常に快適に感じます;)

+0

非常に洞察に満ちました、特にモデルに関しては、MVVMパターンを使用してWPFについての知識のない古いプロジェクトのデータクラスに接続できるはずです。興味深いことに、RoutedEventsとRoutedCommandsはMVVMにはあまり適していないと私は考えていましたが、MVVMなどのデカップリングパターンで使用されるようになったと思います。フィードバックをお寄せいただきありがとうございます。 –

+0

このフィードバックに基づいてこの例をリファクタリングし、ロジックをViewModelに入れます。http://stackoverflow.com/questions/857820/big-smart-viewmodels-dumb-views-and-any-model-the-best- mvvm-approach –

+0

あなたはポイントを打つ... – Marc

2

私はThomasに同意します。 WPFのarchitecturing上の誰にも私のアドバイスは、次のようになります。などがないINotifyPropertyChange、状態の追跡、BL、と

  • 平野POCOエンティティ
  • ビューを通知
  • シンプルで小型のviewmodelsは、ジャストインタイム
  • 複雑なデータ階層を避けるスマートナビゲーションシステムを使用した単純な再利用可能なUIと複雑な基礎となるのviewmodels
  • シンプルな依存関係を維持するためのビューファースト・アプローチとMVVMタスクまたはRXとの非同期操作
  • シンプルなテーマ
  • 複雑な堅牢なUIは、ちょうど
  • は私たちに躊躇しないでくださいWPFs UI組成物の利点と結合能を取り、それをシンプルに保ちます(フォームやリストなど)を動的に生成し、宣言的な目の構成(ほとんどの場合に適用)にかなりの時間を節約するためのコードビハインド、そして私にとっては2015年の必需品です。拡張メソッドを使用してそのためのFluent APIを作成します。 RelayCommandsとRoutedCommandsについて
関連する問題