Silverlight ASync调用Service覆盖类成员

时间:2014-03-26 10:21:46

标签: c# wcf silverlight asynchronous

我使用silverlight访问网络服务以请求一些数据。这个调用是异步的。我(我想)在对它做一些操作之后必须把这些数据放在一个类成员中,所以我以后可以访问它。

public class CardPrinter
{
    // The card to be printed
    private UIElement printCard;

    public void PrintStaffCard(string p_persoons)
    {
        Debug.WriteLine(p_persoons);

        foreach (string persoon in p_persoons.Split(','))
        {
            int p_persoon = Convert.ToInt32(persoon.Trim());
            this.GetStaffData(p_persoon);
        }
    }

    private void GetStaffData(int p_persoon)
    {
        PictureServiceClient proxy = new PictureServiceClient();

        proxy.GetPersonelCardInfoCompleted += this.Proxy_GetPersonelCardInfoCompleted;
        proxy.GetPersonelCardInfoAsync(p_persoon);
    }

    private void Proxy_GetPersonelCardInfoCompleted(object sender, GetPersonelCardInfoCompletedEventArgs e)
    {
        if (e.Error != null)
        {
            Debug.WriteLine(e.Error.Message);
        }
        else
        {
            this.SendStaffCardToPrinter(e.Result);
        }
    }

    private void SendStaffCardToPrinter(CardInfo.CardInfo card)
    {
        Canvas canvas = new Canvas()

        //Do some stuff

        this.printCard = canvas;

        PrintDocument pd = new PrintDocument();
        pd.PrintPage += new EventHandler<PrintPageEventArgs>(this.Pd_PrintPage);

        pd.Print(card.accountNr, null, true);
    }

    private void Pd_PrintPage(object sender, PrintPageEventArgs e)
    {
        e.PageVisual = this.printCard;
    }

}

问题出在printCard变量中。有时它仍包含来自foreach中先前异步调用的数据。

如果我能确保foreach中的调用完全完成,那就不会有问题,但不确定如何执行此操作,如果这是处理此问题的正确方法。

处理这种情况的最佳方法是什么?

2 个答案:

答案 0 :(得分:1)

GetPersonalCardInfoAsync方法应该有一个重载,您可以传递UserState参数。您可以在拨打电话时将printCard传递给您,并在Proxy_GetPersonelCardInfoCompleted稍后再访问。

private void GetStaffData(int p_persoon, UIElement printCard)
{
    PictureServiceClient proxy = new PictureServiceClient();

    proxy.GetPersonelCardInfoCompleted += this.Proxy_GetPersonelCardInfoCompleted;
    proxy.GetPersonelCardInfoAsync(p_persoon, printCard);
}


private void Proxy_GetPersonelCardInfoCompleted(object sender, GetPersonelCardInfoCompletedEventArgs e)
{
    UIElement printCard = (UIElement)e.UserState;
    // do stuff 
}

答案 1 :(得分:1)

通过使用TaskCompletionSource将异步方法从基于事件的方法转换为基于任务的方法,可以使代码更易于使用。然后你可以摆脱变量,方法的使用就像使用同步方法一样。

我还没有测试过这个,但它应该接近你需要的。您可能还会发现following article很有用。还有以下帖子Nested Asynchronous function in Silverlight

public class CardPrinter
{
    public void PrintStaffCard(string p_persoons)
    {
        Debug.WriteLine(p_persoons);

        foreach (string persoon in p_persoons.Split(','))
        {
            int p_persoon = Convert.ToInt32(persoon.Trim());
            var cardInfo = await this.GetStaffDataAsync(p_persoon);
            await this.SendStaffCardToPrinterAsync(cardInfo);
        }
    }

    private Task<CardInfo.CardInfo> GetStaffDataAsync(int p_persoon)
    {
        var tcs = new TaskCompletionSource<CardInfo.CardInfo>();

        PictureServiceClient proxy = new PictureServiceClient();

        proxy.GetPersonelCardInfoCompleted += (s, e) =>
        {
            if (e.Error != null)
            {
                Debug.WriteLine(e.Error.Message);
                tcs.SetException(e.Error);
            }
            else
            {
                tcs.SetResult(e.Result);
            }
        };

        proxy.GetPersonelCardInfoAsync(p_persoon);

        return tcs.Task;
    }

    private Task SendStaffCardToPrinterAsync(CardInfo.CardInfo card)
    {
        Canvas canvas = new Canvas();

        //Do some stuff

        var tcs = new TaskCompletionSource<object>();

        PrintDocument pd = new PrintDocument();

        pd.PrintPage += (s, e) => 
        {
            e.PageVisual = canvas;
            tcs.SetResult(null);
        };

        pd.Print(card.accountNr, null, true);

        return tcs.Task;
    }
}