4

したがって、MVVMパターン(Caliburn.Micro)を使用するWPFアプリケーションがあります。ビューとビューモデルを接続しましたが、基本的に不足しているのはデータです。データは、WCFサービス、ローカルストレージ、またはメモリ/キャッシュのいずれかから「オンデマンド」で取得されます。これは、オフラインモードを許可し、不必要なサーバー通信を回避するためです。もう1つの要件は、UIスレッドがブロックされないように、データが非同期で取得されることです。

そこで、ビューモデルがデータを要求するために使用する、ある種の「AssetManager」を作成することを考えていました。

_someAssetManager.GetSomeSpecificAsset(assetId, OnGetSomeSpecificAssetCompleted)

これは非同期呼び出しであることに注意してください。しかし、私はいくつかの異なる問題に遭遇します。同じアセットが異なるビューモデルによって(ほぼ)同時に要求された場合、不必要な作業を行わず、両方がバインドできる同じオブジェクトを取得するようにするにはどうすればよいですか?

私が正しいアプローチを取っているかどうかはわかりません。私はReactiveFrameworkを少し見てきましたが、このシナリオでどのように使用するかわかりません。私が使用できるフレームワーク/テクニック/パターンに関する提案はありますか?これはかなり一般的なシナリオのようです。

4

4 に答える 4

4
Dictionary<int, IObservable<IAsset>> inflightRequests;

public IObservable<IAsset> GetSomeAsset(int id)
{
    // People who ask for an inflight request just get the
    // existing one
    lock(inflightRequests) {
        if inflightRequests.ContainsKey(id) {
            return inflightRequests[id];
        }
    }

    // Create a new IObservable and put in the dictionary
    lock(inflightRequests) { inflightRequests[id] = ret; }

    // Actually do the request and "play it" onto the Subject. 
    var ret = new AsyncSubject<IAsset>();
    GetSomeAssetForReals(id, result => {
        ret.OnNext(id);
        ret.OnCompleted();

        // We're not inflight anymore, remove the item
        lock(inflightRequests) { inflightRequests.Remove(id); }
    })

    return ret;
}
于 2012-04-10T06:30:33.853 に答える
1

私はあなたをこのように設定しますAssetManager

public interface IAssetManager
{
    IObservable<IAsset> GetSomeSpecificAsset(int assetId);
}

Subject<IAsset>内部的には、非同期で入力したを返す必要があります。それを正しく行うと、への呼び出しごとに1つの呼び出ししかありませんGetSomeSpecificAsset

于 2012-04-10T06:24:41.360 に答える
1

プロキシ パターンとイベントを使用すると、同期データと非同期データの両方を提供できます。プロキシが同期呼び出しのキャッシュされた値を返し、非同期データを受信したときにイベントを介してビュー モデルに通知するようにします。プロキシは、データ要求を追跡し、サーバー接続を調整するように設計することもできます (たとえば、「参照カウント」呼び出し、データ要求/データ受信フラグなど)。

于 2012-04-09T16:30:37.193 に答える
1

データの受信時に呼び出されるデリゲートを渡すメソッド呼び出しで成功しました。リクエストが発生しているかどうかを判断するブール値フィールドをチェックすることで、(リクエストが現在発生している場合) 全員に同じデータを保持するという要件を重ねることができます。呼び出す必要があるデリゲートのローカル コレクションを保持して、データが最終的に受信されたときに、呼び出すデリゲートを含むクラスがそれらを反復処理して、新しく受信したデータを渡すことができるようにします。

これらの行に沿ったもの:

public interface IViewModelDataLoader{
    void LoadData(AssignData callback);
}

public delegate void AssignData(IEnumerable<DataObject> results);

このインターフェイスを実際に実装するクラスは、データが完了したときに誰に通知するかについて、実行中の集計を保持できます (シングルトン モデルを想定)。

public class ViewModelDataLoader : IViewModelDataLoader{
    private IList<AssignData> callbacksToCall;
    private bool isLoading;

    public void LoadData(AssignData callback){
        callbacksToCall.add(callback);
        if (isLoading) { return; }

        // Do some long running code here
        var data = something;
        // Now iterate the list
        foreach(var item in callbacksToCall){
           item(data);
        }
        isLoading = false;
    }
 }
于 2012-04-09T15:49:25.263 に答える