2

したがって、これはより一般的な形式で回答された可能性がありますが、ここではより具体的なケースがあり、これをどのように解決すべきかについてのアイデアを得たいと考えています。私は WPF アプリケーションを作成していて、MVVM パターンを使用しようとしています (このパターンを初めて使用します)。

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

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

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

4

3 に答える 3

2

MVVM で のプロパティを から に公開する方法は 2 つありますModelViewモデルViewModel全体をビューに公開する方法と、ビューが 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");
            }
        }
    }
}

前もっての作業が少し増えますが、メンテナンスがはるかに簡単になります

別の方法として、クラスを上書きして、関心のあるメソッドをObservableCollection実装することもできますList<T>。たとえば、現在、、、および をObservableCollectionEx実装しているクラスがあります。興味がある場合は、ここにメソッドの例があります。ContainsIndexOfAddRangeRemoveRangeSort

もちろん、これは、そのプロパティを使用する他のすべてを更新して、ObservableCollectionEx<T>代わりにを使用する必要があることも意味します。List<T>

于 2012-04-10T20:09:18.353 に答える
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));
        }
    }
}
于 2012-04-11T17:15:34.450 に答える
0

Mergedこれを解決する 1 つの方法は、 で呼び出されている Viper オブジェクトにイベントを追加することMergeWith()です。このようにして、ビューモデルはそのイベントをサブスクライブし、更新が発生するとそれ自体を更新できます。

于 2012-04-10T19:36:06.757 に答える