Как я могу использовать вложенные вызовы Async (WCF) в циклах foreach в Silverlight? - PullRequest
1 голос
/ 29 марта 2010

Следующий код содержит несколько вложенных асинхронных вызовов в некоторых циклах foreach. Я знаю, что вызовы silverlight / wcf называются асинхронно, но как я могу убедиться, что мои объекты wcfPhotographers, wcfCategories и wcfCategories готовы до запуска цикла foreach? Я уверен, что поступаю неправильно, и был бы признателен за помощь, которую вы могли бы оказать.

    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 ]

3 голосов
/ 29 марта 2010

Да, прежде чем вы сможете перейти к следующему шагу алгоритма, вам нужно получить результат предыдущего шага, что может быть сложно, если вам нужно использовать асинхронные методы.

Если этого не происходит в потоке пользовательского интерфейса, вы можете просто заблокировать и дождаться ответа. Например, имейте каждый «завершенный» сигнал метода (используя любые примитивы синхронизации, доступные в Silverlight; я не знаю, например, есть ли ManualResetEvent, если так, имеет завершенный обратный вызов .Set()), а затем ваш основной Метод PopulateControl вызывает вызов FooAsync () и затем блокируется до тех пор, пока ManualResetEvent не подаст сигнал (путем вызова .Wait()).

Если это в потоке пользовательского интерфейса, и вам действительно нужно написать неблокирующее решение, то гораздо, намного сложнее правильно написать это в C #. Вместо этого вы можете рассмотреть возможность использования F #, где async s обеспечивает хорошую модель программирования для неблокирующих вызовов.

EDIT:

Пример псевдокода для блокировки результатов:

// 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 голосов
/ 29 марта 2010

Кроме того, для каждого асинхронного метода, который вы используете для заполнения коллекции, вы можете создать вспомогательный метод, который будет возвращать 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};

Этот запрос вернет вам список триплетов (Фотограф, Категория, Подкатегория). Теперь все, что вам нужно сделать, это подписаться на него и объединить его с объектами, которые вы используете на клиенте, что должно быть довольно просто.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...