將它直接下調到fundementals實際上你要求的是能夠對執行異步任務的API進行同步調用,但只有在該異步任務完成時纔會返回。爲了說明另一種想要將異步操作的Begin和End階段重新組合爲單個原子同步操作的方式。
獲得的唯一方法是阻止進行調用的線程,直到達到異步操作的結束階段。由於多種原因,這不是一個好主意。
如果您認真對待使用Silverlight,您必須吞併其異步特性並在該框架中使用,而不是試圖強制它回到同步系統中。
轉換同步對異步
有這個blog約同步碼轉換爲異步代碼的讀取。看了那現在讓我們試想一下,你的代碼使用名爲DownloadYourDataObjects
在新的DLL同步方法,它有這個虛構的簽名: -
public IEnumerable<YourDataObject> DownloadYourDataObjects(Uri source);
在內部它使用WebClient
從REST基本服務下載一個字符串,並將其轉換到一組YourDataObject
實例。虛同步代碼,以顯示這組數據可能是: -
private void btnLoadMyData_Click(object sender, RoutedEventArgs e)
{
try
{
LoadMyData();
}
catch (Exception err)
{
// Oops something bad happened show err.
}
}
private void LoadMyData()
{
DataItemsListBox.ItemsSource = DownloadYourDataObjects(someUri);
}
由於Silverlight WebClient
是異步的,我們需要把這個整個的代碼轉換鏈以異步方式工作。
使用博客中的AsyncOperationService
,我們首先需要將DownloadYourDataObjects
轉換爲返回AsyncOperation
。這將有這樣的簽名(見稍後再實現的想法): -
public AsyncOperation DownloadYourDataObjects(Uri source, Action<IEnumerable<YourDataObject>> returnResult);
的使用代碼將然後是這個樣子: -
private void btnLoadMyData_Click(object sender, RoutedEventArgs e)
{
LoadMyData().Run(err =>
{
if (err != null)
{
// Oops something bad happened show err.
}
});
}
private IEnumerable<AsyncOperation> LoadMyData()
{
yield return DownloadYourDataObjects(someUri, result =>
{
DataItemsListBox.ItemsSource = result;
});
}
這看起來豆蔻OTT但在事實上它並不比原來的「同步」版本多得多。在這種簡單的情況下,LoadMyData
只有一個操作要執行。更復雜的版本LoadMyData
可能有多個其他操作也需要異步。在這種情況下,這些操作將只是代碼中的其他yield
點,LoadMyData
的基本邏輯結構不會從原始同步版本變化很多。
這裏是您的DLL將提供的DownloadYourDataObjects
的實現示例。
public AsyncOperation DownloadYourDataObjects(Uri source, Action<IEnumerable<YourDataObject>> returnResult)
{
return (completed) =>
{
WebClient client = new WebClient();
client.DownloadStringCompleted += (s, args) =>
{
try
{
returnResult(ConvertStringToYourDataObjects(args.Result));
completed(null);
}
catch (Exception err)
{
completed(err);
}
};
client.DownloadStringAsync(source);
};
}
將您的用戶界面綁定到一個屬性,該屬性通過ObservableCollection返回IEnumerable。這樣,用戶界面可以綁定到一個空列表,並且數據以異步或同步方式返回時,只需簡單地自行更新。 –
2011-04-29 21:41:41