我使用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中的调用完全完成,那就不会有问题,但不确定如何执行此操作,如果这是处理此问题的正确方法。
处理这种情况的最佳方法是什么?
答案 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;
}
}