2010-03-28 45 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