2012-04-09 59 views
3

所以我有一個使用MVVM模式(Caliburn.Micro)的WPF應用程序。我得到了觀點和觀點模型,基本上缺少的是數據。數據將從WCF服務,本地存儲或內存/緩存中「按需」檢索 - 原因是允許離線模式並避免不必要的服務器通信。另一個要求是數據是異步檢索的,所以UI線程不會被阻塞。MVVM和異步數據訪問

所以我想創造某種「AssetManager」的的的ViewModels使用請求數據:

_someAssetManager.GetSomeSpecificAsset(assetId, OnGetSomeSpecificAssetCompleted) 

請注意,這是一個異步調用。儘管我遇到了一些不同的問題。如果同一資產在不同的視圖模型下(大致)同時被請求,我們如何確保我們不做不必要的工作,並且它們都獲得了我們可以綁定的相同對象?

不知道我有正確的做法。我一直在看Reactive Framework - 但我不知道如何在這種情況下使用它。我可以使用任何有關框架/技巧/模式的建議?這似乎是一個相當普遍的情況。

回答

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; 
} 
+1

現在,第一個要求提供id 5的人得到了真正的請求,而其他所有連續詢問的人都會聽到相同的請求。 – 2012-04-10 06:36:35

+0

真棒:)。謝謝。 – Pking 2012-04-10 07:34:36

+1

更聰明的是,如果你實際上沒有從字典中刪除這個項目,它將永遠不需要再次請求資源。我沒有這樣做,因爲它是內存泄漏(即該字典變得越來越大),並且編碼某種MRU緩存策略會使此示例更少說明:) – 2012-04-10 07:38:59

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; 
    } 
} 
+0

謝謝。試過一些非常相似的東西。我試圖使用Monitor.TryEnter(obj)來保證線程安全(從未使它工作),我放棄了。也許我會再試一次。 – Pking 2012-04-09 16:21:46

+0

@Pking也許嘗試'lock(){}'構造..我已經爲這個問題鍵入了一些代碼,但它是不完整的.. – 2012-04-09 16:30:58

1

使用代理模式和事件可以提供同步和異步數據。讓您的代理爲同步調用返回緩存值,並在接收異步數據時通過事件通知視圖模型。代理也可以用來追蹤數據請求和油門服務器連接(例如,「引用計數」呼籲,請求/數據的數據接收標誌等)

+0

Interresting,我會檢查出來。 – Pking 2012-04-09 17:28:37

1

我會成立,你AssetManager這樣的:

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

在內部,您需要返回異步填充的Subject<IAsset>。做對了,每次打電話給GetSomeSpecificAsset只需要一個電話。