2010-03-28 62 views
1

以下代碼在一些foreach循環中包含一些嵌套的異步調用。我知道silverlight/wcf調用被稱爲asyncrously - 但我怎麼能確保我的wcfPhotographers,wcfCategories和wcfCategories對象在foreach循環開始之前就準備好了?我敢肯定,我正在以這種錯誤的方式去做 - 並希望能給你一個幫助。如何在Silverlight的foreach循環中使用嵌套異步(WCF)調用?

private void PopulateControl() 
    { 

     List<CustomPhotographer> PhotographerList = new List<CustomPhotographer>(); 

     proxy.GetPhotographerNamesCompleted += proxy_GetPhotographerNamesCompleted; 
     proxy.GetPhotographerNamesAsync(); 


     //for each photographer 
     foreach (var eachPhotographer in wcfPhotographers) 
     { 

      CustomPhotographer thisPhotographer = new CustomPhotographer(); 

      thisPhotographer.PhotographerName = eachPhotographer.ContactName; 
      thisPhotographer.PhotographerId = eachPhotographer.PhotographerID; 

      thisPhotographer.Categories = new List<CustomCategory>(); 

      proxy.GetCategoryNamesFilteredByPhotographerCompleted += proxy_GetCategoryNamesFilteredByPhotographerCompleted; 
      proxy.GetCategoryNamesFilteredByPhotographerAsync(thisPhotographer.PhotographerId); 


      // for each category 
      foreach (var eachCatergory in wcfCategories) 
      { 

       CustomCategory thisCategory = new CustomCategory(); 

       thisCategory.CategoryName = eachCatergory.CategoryName; 
       thisCategory.CategoryId = eachCatergory.CategoryID; 

       thisCategory.SubCategories = new List<CustomSubCategory>(); 

       proxy.GetSubCategoryNamesFilteredByCategoryCompleted += proxy_GetSubCategoryNamesFilteredByCategoryCompleted; 
       proxy.GetSubCategoryNamesFilteredByCategoryAsync(thisPhotographer.PhotographerId,thisCategory.CategoryId); 

       // for each subcategory 
       foreach(var eachSubCatergory in wcfSubCategories) 
       { 
        CustomSubCategory thisSubCatergory = new CustomSubCategory(); 

        thisSubCatergory.SubCategoryName = eachSubCatergory.SubCategoryName; 
        thisSubCatergory.SubCategoryId = eachSubCatergory.SubCategoryID; 
       } 


       thisPhotographer.Categories.Add(thisCategory); 
      } 

      PhotographerList.Add(thisPhotographer); 
     } 

     PhotographerNames.ItemsSource = PhotographerList; 
    } 




    void proxy_GetPhotographerNamesCompleted(object sender, GetPhotographerNamesCompletedEventArgs e) 
    { 
     wcfPhotographers = e.Result.ToList(); 
    } 


    void proxy_GetCategoryNamesFilteredByPhotographerCompleted(object sender, GetCategoryNamesFilteredByPhotographerCompletedEventArgs e) 
    { 
     wcfCategories = e.Result.ToList(); 
    } 

    void proxy_GetSubCategoryNamesFilteredByCategoryCompleted(object sender, GetSubCategoryNamesFilteredByCategoryCompletedEventArgs e) 
    { 
     wcfSubCategories = e.Result.ToList(); 
    } 

回答

3

是的,然後才能與算法的繼續執行下一步,你需要已經得到了前面的步驟,它可以是很難當你必須使用異步方法的結果。

如果這不在UI線程上發生,那麼您可以阻止並等待響應。例如,已分別「已完成」的方法信號(使用任何同步原語都可以在Silverlight,我不知道隨便例如,如果ManualResetEvent的是存在的,如果是的話,必須完成的回調調用.Set()),然後讓你的主要PopulateControl方法調用FooAsync()調用,然後阻塞,直到ManualResetEvent信號(通過調用.Wait())。

如果這是在UI線程,你真的需要寫一個無阻塞的解決方案,這是非常非常難的C#代碼正確這件事。您可以考慮使用F#,而async爲非阻塞調用提供了一個很好的編程模型。

編輯:

僞代碼示例阻塞的結果:

// class-level 
ManualResetEvent mre = new ManualResetEvent(false); 
// some method that needs to make WCF call and use results 
void Blah() { 
    // yadda yadda 
    proxy.FooCompleted += (o,ea) => { ... mre.Set(); }; 
    proxy.FooAsync(...); 
    mre.WaitOne(); // block until FooCompleted 
    // use results from FooCompleted now that they're here 
    // mre.Reset() if you intend to use it again later 
} 

我用的λ爲FooCompleted,但使用一個單獨的方法等你已經是沒關係。

+0

感謝您的回覆 - 可以給我一個僞代碼示例,說明如何實現.Set()&.Wait()乾杯 – 2010-03-28 21:31:27

+0

沒有工作不安全 - 它掛在mre.Wait(); – 2010-03-28 21:50:39

+0

請注意,如果您多次使用它,則必須在調用之間重置()它。 – Brian 2010-03-28 21:59:26

0

另外,對於每一個異步方法您使用來填充你可以創建一個輔助方法,將返回IObservable的集合,然後使用Linq查詢對結果進行分組。

如:

private IObservable<Photographer> GetPhotographerNames() 
{ 
    var photographers = Observable 
     .FromEvent<GetPhotographerNamesCompletedEventArgs>(proxy, "GetPhotographerNamesCompleted") 
     .Prune() 
     .SelectMany(e => e.EventArgs.Result.ToObservable()); 

    proxy.GetPhotographerNamesAsync(); 

    return photographers; 
} 

而且類似:

private IObservable<Category> GetCategoryNamesFilteredByPhotographer(int photographerId)  { ... } 
private IObservable<SubCategory> GetSubCategoryNamesFilteredByCategory(int photographerId, int categoryId) { ... } 

現在你可以寫一個LINQ查詢:

var pcs = from p in GetPhotographerNames() 
      from c in GetCategoryNamesFilteredByPhotographer(p.PhotographerId) 
      from s in GetSubCategoryNamesFilteredByCategory(p.PhotographerId, c.CategoryId) 
      select new {p, c, s}; 

此查詢將返回三元組列表(攝影師,類別,子類別)現在,您只需要訂閱它並將其聚合到您在其上使用的對象e客戶端應該是非常簡單的。

+0

您好感謝您的建議哪位框架/ Silverlight的版本做這一目標? – 2010-03-29 13:38:21

+0

將工作在SL3但要求反應性擴展的下載(http://msdn.microsoft.com/en-us/devlabs/ee794896.aspx) – 2010-03-29 14:26:12