在 Silverlight 5 項目中使用 async/await
.Net 4.5 提供了 async/await 讓異步編程回歸同步, 不過, async/await 不是只能在 .Net 4.5 下才能使用, 通過使用 Async Targeting Pack 就可以在 .Net 4.0 以及 Silverlight 5 項目中使用 async/await。
先來看一段 Silverlight 代碼, 不使用 async/await 時是這樣子的:
private void DistanceTestButtonClick(object sender, RoutedEventArgs routedEventArgs) {
// 假設這是用戶輸入的坐標
var point1 = GeometryUtil.CreateMapPointWgs84(113.3, 23.07);
// 假設用戶輸入目的地坐標
var point2 = GeometryUtil.CreateMapPointWgs84(110.3, 20);
// 全局地圖控件
var map = App.ObjContainer.Resolve(typeof(Map));
// 從當前 UI 上下文創建 TaskScheduler
var uiContext = TaskScheduler.FromCurrentSynchronizationContext();
// 創建三個幾何服務
var geoSvc1 = GeoFactory.CreateGeometryService();
var geoSvc2 = GeoFactory.CreateGeometryService();
var geoSvc3 = GeoFactory.CreateGeometryService();
// 將用戶輸入的坐標投影為地圖的坐標系坐標
var task1 = geoSvc1.ProjectPointAsync(point1, map.SpatialReference);
task1.ContinueWith(t1 => {
point1 = task1.Result;
// 目的地坐標投影為地圖坐標
var task2 = geoSvc2.ProjectPointAsync(point2, map.SpatialReference);
task2.ContinueWith(t2 => {
point2 = task2.Result;
var buffParam = this.CreateBufferParameters(point2);
var buffTask = geoSvc3.BufferTaskAsync(buffParam);
// 做一次緩沖查詢
buffTask.ContinueWith(t3 => {
var buffGeometry = buffTask.Result.First();
var disParam = new DistanceParameters {
DistanceUnit = LinearUnit.Meter,
Geodesic = true
};
// 求距離
var disTask1 = geoSvc1.DistanceTaskAsync(point1, point2, disParam);
disTask1.ContinueWith(t4 => {
var disTask2 = geoSvc2.DistanceTaskAsync(point1, buffGeometry.Geometry, disParam);
disTask2.ContinueWith(t5 => {
//最后求得最終距離
var dis1 = disTask1.Result;
var dis2 = disTask2.Result;
}, uiContext);
}, uiContext);
}, uiContext);
}, uiContext);
}, uiContext);
}
看上面的代碼, 做 Silverlight 開發的可真傷不起啊, Silverlight 閹割了所有的同步方法, 只能做異步查詢, 本來是可以放在后臺線程中模擬同步的,可偏偏 ArcGIS 提供的 Silverlight API 在回調函數中創建了 UI 元素以及 DepedencyObject , 想放到后臺線程中計算也不行, 真是悲劇。
下面就請出 Async Targeting Pack 來拯救一下吧, 打開 NuGet 管理器, 輸入 await 查詢, 找到 Async Targeting Pack for Visual Studio 11 , 然后下載并添加引用到 Silverlight 項目, 開始用 async/await 改造上面的代碼, 最終的結果如下, 看看是不是清爽了好多呢?
async private void DistanceTestButtonClick(object sender, RoutedEventArgs routedEventArgs) {
var point1 = GeometryUtil.CreateMapPointWgs84(113.3, 23.07);
var point2 = GeometryUtil.CreateMapPointWgs84(110.3, 20);
var map = App.ObjContainer.Resolve(typeof(Map));
var geoSvc1 = GeoFactory.CreateGeometryService();
var geoSvc2 = GeoFactory.CreateGeometryService();
var geoSvc3 = GeoFactory.CreateGeometryService();
point1 = await geoSvc1.ProjectGeometryAsync(point1, map.SpatialReference) as MapPoint;
point2 = await geoSvc2.ProjectGeometryAsync(point2, map.SpatialReference) as MapPoint;
var buffParam = this.CreateBufferParameters(point2);
var buffGeometry = (await geoSvc3.BufferTaskAsync(buffParam)).First();
var disParam = new DistanceParameters {
DistanceUnit = LinearUnit.Meter,
Geodesic = true
};
var dist1 = await geoSvc1.DistanceTaskAsync(point1, point2, disParam);
var dist2 = await geoSvc2.DistanceTaskAsync(point1, buffGeometry.Geometry, disParam);
var d = dist2 - dist1;
}
這樣編譯出來的 xap 包只是多了一個 dll, 依然可以在 Silverlight5 下運行, 客戶端不需要安裝任何軟件。
大家趕快升級 VS2012 吧, 異步編程回歸同步了!
張志敏所有文章遵循創作共用版權協議,要求署名、非商業 、保持一致。在滿足創作共用版權協議的基礎上可以轉載,但請以超鏈接形式注明出處。
本博客已經遷移到 GitHub , 圍觀地址: https://beginor.github.io/
浙公網安備 33010602011771號