如何在Silverlight中的foreach循环中使用嵌套的Async(WCF)调用?

时间:2010-03-28 20:23:46

标签: wcf silverlight nested foreach asynchronous

以下代码在一些foreach循环中包含一些嵌套的异步调用。我知道silverlight / wcf调用是异步调用的 - 但是如何在foreach循环开始之前确保我的wcfPhotographers,wcfCategories和wcfCategories对象已准备就绪?我确信我会以错误的方式解决这个问题 - 并且非常感谢你能给予的帮助。

    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();
    }

2 个答案:

答案 0 :(得分: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
}

我使用lambda作为FooCompleted,但是使用像你一样的单独方法也很好。

答案 1 :(得分:0)

或者,对于用于填充集合的每个异步方法,您可以创建一个将返回IObservable的辅助方法,然后使用Linq查询对结果进行分组。

E.g:

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

此查询将返回三元组列表(摄影师,类别,子类别)现在,您只需订阅它并将其聚合到您在客户端上使用的对象,这应该非常简单。

相关问题