2

私のアプリケーションのモデルには、それぞれが「子」のリストを参照する「親」のリストがあります(たとえば、それぞれがプレーヤーのリストを含むフットボールチームのリスト)。

このリストをツリービューで視覚化します。ツリー用のviewmodelクラスとfootballteam用のviewmodelクラスを作成しました(これを「footballteamViewModel」と呼びましょう)。ツリーのクラスは、footballteamViewModel-itemsを含むObservableCollectionを保持します。ツリーのitems-sourceは、このObservableCollectionです。初期化中に、モデル内のすべてのフットボールチームに対して対応するfootballteamViewModelオブジェクトを作成し、それをObservableCollectionに追加します。

問題は、モデル内のフットボールチームのリストをツリーの外側から変更できるため、ツリーを更新したいということです。したがって、誰かがモデルのリストからフットボールチームを削除した場合、footballteamViewModel-itemsのObservableCollection内の対応するアイテムを削除する必要があります。

モデルのフットボールチームのリストをビューに直接バインドすることはできません。そのため、モデル内のコレクションが変更されるたびに、ViewModel内のObservableCollectionを何らかの方法で更新する必要があります。

これを処理する私の方法は、モデルでObservableCollectionを使用し、ViewModelのcollectionChanged-eventに登録することです。これにより、モデルコレクションが変更されるたびにViewModel(footballteamViewModelオブジェクトのObservableコレクション)を更新します。しかし、これは「正しい」とは感じません。もっと良い方法はありますか?

これを入力しているときに、まったく同じ問題を説明する別の投稿を見つけました:WPF / MVVM:ドメインモデルコレクションをViewModelに委任します。そこでの答えは、私がこの問題を解決する方法が完全に間違っているわけではないことを私に促しますが、それでも別の方法があるのだろうかと思います。

編集:あなたが提供した最初の回答から、私の質問に対する明確な回答はないと思います。それらはすべて役に立ちましたので、それらすべてを読む価値があります。Bindable Linq / Continuous Linq / Opticalsフレームワークを参照して答えをマークするだけです。これは、私の質問に最も遭遇する他の人に役立つと思うからです。

4

4 に答える 4

3

これは、MVVMの最も厄介なスポットの1つです。

私がしばらく前に行ったことの1つは、次のように、両方のコレクションに対して操作を実行する修飾子メソッド(Add、Remove)ViewModelCollection<T>を継承し、持つaを作成することです。ObservableCollection<T>

    public interface IViewModel<T>
{
    T WrappedModel { get; }
}

public class ViewModelCollection<T,M> : ObservableCollection<T,M> where T : IViewModel<M>
{
    private IList<M> _baseCollection;

    public ViewModelCollection(IList<T> baseCollection)
    {
        _baseCollection = baseCollection;
    }

    public override void Add(T objectToAdd)
    {
        IViewModel<M> vm = objectToAdd as IViewModel<M>;
        if (vm != null)
        {
            this.Add(objectToAdd);
            _baseCollection.Add(vm.WrappedModel);
        }
    }

    public override void Remove(T objectToRemove)
    {
        IViewModel<M> vm = objectToRemoveas IViewModel<M>;
        if (vm != null)
        {
            this.Remove(objectToRemove);
            _baseCollection.Remove(vm.WrappedModel);
        }
    }
}

今のところ、これはまったく行いません。モデルにINotifyPropertyChanged機能を追加するCastleプロキシを使用するだけで、ボイラープレートコードを大幅に節約できます。

コードをテストしておらず、メモリから入力しただけであることに注意してください。

于 2012-05-04T09:47:05.583 に答える
2

モデルコレクションをビューに直接バインドすることはできません(つまり、ビューモデルはモデルコレクションに含まれるもののコピーを使用して独自に作成する必要がObservableCollectionあります)。さらに、モデルコレクションが変更されたときにビューをライブで更新する必要があります。 (つまり、モデルはそのような変更をビューモデルに通知する必要があり、ビューモデルはその内部コピーを更新する必要があります)。

これらすべては、実際には多くの小刻みに動く余地を残しません。興味深いかもしれない1つのバリエーションは、モデルのコレクションを読み取り/書き込みIEnumerableにすることです。この場合、モデルのコンシューマーは、コレクションを変更する必要があるときはいつでも、モデルを新しいインスタンスと交換する必要があります。その見返りとして、ビューモデルの「同期を維持する」コードを簡略化しINotifyPropertyChangedて、コレクションプロパティで同期をトリガーできます。

于 2012-05-04T09:42:16.370 に答える
1

ソリューションはまったく間違っていませんが、BindableLinq、ContinuousLinq、Obticsなど、ソリューションを簡単に実装するのに役立つライブラリがいくつかあります。ここでそれらについて議論があります。悲しいことに、それらのどれもさらなる開発中ではないようです。

Clinqでの私の個人的な経験は素晴らしく、私はまだそれを使用していますが、あなたの場合にはうまくいくはずです。

于 2012-05-04T09:43:19.967 に答える
1

遅いですが、他の人を助けるかもしれません...

このトピックに関するこの優れた3部構成のブログ投稿シリーズをお読みください。
パート3はコレクションについてであり、いくつかの解決策を示しています-私を大いに助けます

MVVM:ラップするかラップしないか?ViewModelはモデルをどのくらいラップする必要がありますか?

于 2012-10-10T02:52:04.447 に答える