2012-04-10 13 views
2

これはより一般的な形で回答されているかもしれませんが、ここではより具体的なケースがあり、これをどのように解決すべきかを知りたいと思います。私はWPFアプリケーションを作成し、MVVMパターンを使用しようとしています(初めてこのパターンを使用します)。WPFリストとObservableCollections

私のドメインオブジェクトであるViperにはいくつかのプロパティとコレクションがあり、既存のいくつかのアプリケーションで使用されています。私は新しいWPFアプリケーションでバインドしたいすべてのプロパティにINotifyPropertyChangedを実装しました。私は今、ドメインオブジェクトとWPFビューの間に座るためのビューモデルを作成しています。問題は、ViperオブジェクトのコレクションであるすべてのプロパティがObservableCollectionsではないリストであることです。 ObservableCollectionsを作ることはできません。これは、このオブジェクトモデルを使用する他のすべてのアプリケーションに影響します(AddRangeなどをサポートしていません)。

この新しいWPFアプリケーションは、(ビューモデルを介して)GUIを制御するために使用されるViperオブジェクトのリストを保持します。物事を少し複雑にするために、アプリはList<Viper>データの形式でデータを受け取ります。アプリはこのViperオブジェクトのリストをループし、入ってくるViperデータを既存のViperにマージします(インデックス別)。これはObservableCollectionではないので、入ってくるViperオブジェクトが既存のViper(List<Event>)のEventsプロパティに項目を追加すると言うと、GUIはイベントのグリッドを更新しません。ビューモデルでList<Event>OC<Event>に変換しても、それはビューモデルではないので、ビューモデルではなくすべてのプロパティとコレクションのこのマージを行う基盤となるViperオブジェクトです。 Viperオブジェクトとすべてのサブオブジェクトは、受信データのマージ方法を決定するカスタムMergeWith()関数を実装しています。いくつかは、置き換えを実行し、いくつかは追加し、いくつかの更新を行います。

この状況を処理する適切な方法は何ですか?不明な点があれば教えてください。

答えて

0

この問題を解決する1つの方法は、で呼び出されているViperオブジェクトにMergedイベントを追加することです。このようにして、ビュー・モデルはそのイベントにサブスクライブし、更新が行われると自動的に更新されます。

2

ViewModelからViewからModelのプロパティを公開するためにMVVMでの2つの方法があります。ビューにモデル全体を暴露することによって、またはビューはViewModelにで気に個々のプロパティを公開することによってのいずれかで。

どちらの方法も同様に有効ですが、多くの場合状況に応じて使います。

UIの変更を通知するように設計されていない既存のModelオブジェクトを使用する必要がある場合は、ビューのViewModelでプロパティを作成する2番目の方法を使用します。例えば

<DataGrid ItemsSource="{Binding SelectedViper.Events}" /> 
public class ViperViewModel : INotifyPropertyChanged 
{ 
    private Viper _selectedViper; 

    public Viper SelectedViper 
    { 
     get { return _selectedViper; } 
     set 
     { 
      if (value != _selectedViper) 
      { 
       _selectedViper= value; 
       RaisePropertyChanged("SelectedViper"); 
      } 
     } 
    } 
} 

はなる:

<DataGrid ItemsSource="{Binding ViperEvents}" /> 
public class ViperViewModel : INotifyPropertyChanged; 
{ 
    private Viper _selectedViper; 
    private ObservableCollection<Event> _viperEvents; 

    public ViperViewModel() 
    { 
     this.PropertyChanged += ViperViewModel_PropertyChanged; 
    } 

    void ViperViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e) 
    { 
     if (e.PropertyName == "SelectedViper") 
     { 
      if (SelectedViper == null) 
       ViperEvents = null; 
      else 
       ViperEvents = new ObservableCollection<Event>(SelectedViper.Events); 
     } 
    } 

    public Viper SelectedViper 
    { 
     get { return _selectedViper; } 
     set 
     { 
      if (value != _selectedViper) 
      { 
       _selectedViper= value; 
       RaisePropertyChanged("SelectedViper"); 
      } 
     } 
    } 

    public ObservableCollection<Event> ViperEvents 
    { 
     get { return _viperEvents; } 
     set 
     { 
      if (value != _viperEvents) 
      { 
       _viperEvents = value; 
       RaisePropertyChanged("ViperEvents"); 
      } 
     } 
    } 
} 

それはアップフロントもう少し作業だが、それは通りメンテナンスはるかに簡単

を作ります代わりに、あなたはを上書きすることができますクラスを作成し、興味のあるメソッドを実装してください(List<T>)。たとえば、Contains,IndexOf,AddRange、およびRemoveRangeを現在実装しているObservableCollectionExクラスがあります。興味がある場合は、Sortメソッドhereの例があります。

もちろん

、これはまた、あなたが基本的にバインディングで同じコレクションを維持し、あなたまでの通知を抑制するために、ここでObservableCollectionEx<T>代わりのList<T>

+1

ええと、Viperオブジェクトが更新されるたびに新しいObservableCollectionを作成すると、新しいエンティティであるため、GUIを再バインドする必要がありますか?その時点で、リストをGUIにバインドし、更新するたびにリバインドすることができます。 ObservableCollectionExアプローチでリストを置き換えると、通知を必要としないViperオブジェクトを使用しているプロジェクトでもパフォーマンスが低下することはありませんか? – mdutra

+0

@mdutra実際の 'Viper'オブジェクトが新しいオブジェクトに変わるときはいつでも、新しい' ObservableCollection'(または 'CollectionViewSource')を作成したいと思います。しかし、既存のオブジェクトを更新するだけであれば、手動で'PropertyChanged'イベントです。 – Rachel

+0

@mdutra 'ObservableCollectionEx'に関する2番目の質問では、必要以上に' PropertyChanged'通知を上げることにパフォーマンス上の問題がありますが、それはメソッドの記述方法によって異なります。例えば、 'AddRange'は各項目を一度に1つずつ追加し、追加された項目ごとに変更通知を出したり、それらを一度に追加したり、単一の変更通知を出すことができます – Rachel

1

アイデアを使用するために、そのプロパティを使用して他のすべてを更新する必要があります意味それらが必要です。

public class Oc<T> : ObservableCollection<T> 
{ 
    private object _lockObject; 
    private bool _suppressChangeNotification; 

    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) 
    { 
     if (!_suppressChangeNotification) 
      base.OnCollectionChanged(e); 
    } 

    public void Merge(IEnumerable<T> newItems) 
    {   
     //don't know if you need a lock..that's your determination 
     lock (_lockObject) 
     { 
      _suppressChangeNotification = true; 
      foreach (var newItem in newItems) 
      { 
       //whatever you do here, insert/remove based on some condition 
       //i'll just put insert for now 
       InsertItem(0,newItem); 
      } 
      _suppressChangeNotification = false; 
      OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); 
     } 
    } 
} 
関連する問題