拥抱新的.Net开发框架,WPF开发者如何向.Net迁移


ArcGIS Runtime 10.2版本中,将WindowsPhone 、WindowsStore以及WPF三大SDK整合成了一个全新的SDK——ArcGISRuntime SDK for Microsoft .Net Framework,简称.Net SDK,同时现有的WPF SDK可以继续使用,但后续会停止更新。因此,Esri建议WPF开发者们向.Net阵营迁移。

顾名思义,新的.NetSDK面向微软的.Net框架,以前的WPF、Windows Phone以及Windows Store平台的开发者们无需再分别下载安装包,直接下载.Net SDK就可以搞定。如何入手新的SDK?WPF已有的开发经验在新的SDK中适用吗?WPF项目如何迁移?本博文将为你提供几个超级实用的tips。

 

开发者们第一个关心的问题可能是,我在WPF开发中积累的诸多经验和技能,是否能用在新的平台中?答案是很鼓舞人心的,那就是.Net SDK开发的技巧与WPF非常接近,你甚至可以将.Net SDK中的Windows Desktop API看成是对现有WPF API的升级,它们拥有许多相同的概念,甚至许多实际的类和类成员的名字都一样。不过,.Net SDK毕竟是基于最新的.NET框架,并加入了许多最新的或者流行的模型和实践在里面,比如MVVM模型和异步处理任务模型等,这意味着它们之间也有些小区别。


第二个可能关心的问题是,我需要将我现有的所有WPF项目都迁移到.Net平台上吗?答案也许是不用。迁移会导致一些问题,你必须单独考虑每个app,评估它们是否要用到新平台中的一些新特性。那些无需使用新特性的app无需迁移,直接使用现有的WPF API即可,我们在未来一段时间仍会继续对现有的WPF SDK提供技术支持,帮助大家解决功能、性能及与ArcGIS的兼容性等问题。

如果app需要使用到新特性,那么最好的办法就是进行迁移。以下是一些实用的迁移方法,让大家可以更加方便的从10.2的WPF SDK迁移到.Net SDK下。

1、使用加速显示模式

1)何为加速显示?

在现有的WPF SDK中,你可以选择使用GIS技术进行优化了的地图渲染引擎,来显示整个地图,或者只显示某个图层的特定子图层,这种渲染引擎被称为“加速显示”。尽管它也可以用来渲染其它的业务图层或者底图,但是用它来展示海量的graphic或者feature是再好不过的了。在所有的ArcGIS Runtime SDK中都有这个地图渲染引擎。在新的.Net版本中,地图被重新设计,使用了高性能的“加速显示”渲染模式来渲染整个地图。

 

2)我如何使用加速显示?

想采用“加速显示”来渲染整个地图需要用到Map类的UseAcceleratedDisplay属性,这是推荐的途径,相应的,可以使用AcceleratedDisplayLayers group layer实现对图层的特定子图层使用“加速显示”渲染,任何位于该grouplayer下的图层都将使用“加速显示”渲染技术,但是记住,你只能在map中添加一个AcceleratedDisplayLayers实例。

下列示例代码是使用WPF的标准渲染功能:

<esri:Map x:Name="MyMap" WrapAround="True">

    <esri:ArcGISTiledMapServiceLayer ID="MyLayer"

       Url="http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer"/>

    <esri:GraphicsLayer ID="MyGraphics" Renderer="{StaticResource MySimpleRenderer}"/>

</esri:Map>

下列代码使用的是ArcGIS Runtime的加速显示渲染功能,使用了UseAcceleratedDisplay属性:

<esri:Map x:Name="MyMap" UseAcceleratedDisplay="True" WrapAround="True">
    <esri:ArcGISTiledMapServiceLayer ID="MyLayer" 
       Url="http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer"/>
    <esri:GraphicsLayer ID="MyGraphics" Renderer="{StaticResource MySimpleRenderer}"/>
</esri:Map>

 

3)为何加速显示模式不是WPF SDK的默认渲染模式?

这是因为,在我们将ArcGISRuntime组件加入到WPF API,并将其发布成为ArcGIS Runtime SDK for WPF之前,WPF API已经是一个独立的产品了,已经不能很好的立即集成加速显示模式,因此我们在WPF中提供了两种渲染模式(WPF原有的普通模式和新的加速显示模式),并将加速显示模式设置为可选的而不是默认的。

4)WPF SDK中使用加速显示会有哪些问题?

你可能遇到的最大的问题是对自定义的XAML符号的支持,因为WPF中的加速显示模式只支持标准的esri symbol和渲染类型(如SimpleMarkerSymbolSimpleRenderer)。而新的.Net SDK使用的是优化了的ArcGISRuntime地图渲染引擎,因此不支持自定义的XAML符号,还有其它的图层和子图层类型不支持加速显示渲染(具体请参见ReleaseNotes),不过大部分都是支持的。另外新的SDK中提供了CompositeSymbol复合符号类型,用户可以通过它来创建自定义的符号。

 

2、异步处理使用WPF SDK 10.2支持的任务模型

1)什么是基于任务的异步处理模型?

编写高性能、响应快的应用程序需要使用基于任务的异步处理模型来应对耗时操作,或者是在单一线程里同时运行多个操作的情况也需要使用到它。管理多线程是件复杂的事情,因此,.Net 4.0中,微软引进了Task(任务)模型来简化多线程应用程序的处理,使得开发者可以使用.Net Task来异步执行代码而不需要去管到底是哪个线程在执行任务。Task同时也提供了许多极好的控制方式,来监听执行失败和执行成功的情况,使得它使用起来非常方便:你只要等待任务执行完成即可。当有多个Task需要执行时,需要明确它们的执行顺序,或者可以等待所有Task都执行完毕后再执行某段代码。C# 5.0版本中更是提供了“async”、“await”等关键词来简化Task的使用。有关async task的更多内容请参考AsynchronousProgramming with Async and Await

 

2)在WPF API中这些Task都藏在了哪里?

ArcGIS Runtime SDK 10.2 for WPF中最引人注目的新特性之一,就是任何异步的方法都会返回一个Task实例来表示一个操作的执行。10.2之前,API同时提供了同步和异步的方法来处理任何可能潜在的耗时操作,在10.2中,这些操作新增了一个后缀为TaskAsync的方法,如QueryTask类有一个同步执行的方法“Execute”,同时其异步执行的方法名在10.2之前为“ExecuteAsync”,在10.2中就变成了“ExecuteTaskAsync”

 

3)我如何使用新的异步处理方法?

在.Net 4.0中使用新的异步处理方法理论上无需任何辅助软件,然而,要想实现新的Task模型的所有功能,并使用“async”和“await”关键字,你必须使用.Net 4.5和VisualStudio 2012及以上的版本,如果非要在4.0中使用,你同时需要下载MicrosoftAsync NuGet包。

 

如果你决定使用Task模型,你需要对你的代码进行一定的修改,这些修改包括取消代理的声明(如命名的event handlers, 内联匿名方法和lambda表达式),并使用await关键字来调用Task的相关方法。异步方法的调用必须包含try/catch语句,因为Task在执行失败时,更有可能抛出异常而不是执行Failed事件。将捕获异常的代码放在catch语句中,这样做有两个好处:可以让你的代码更加简洁和稳定。

 

下面这两个例子就分别使用传统的QueryTask和10.2中的新的Task功能。

第一个例子使用基于事件的模式,使用内联lambda表达式来处理任务执行成功和失败,这种方法下,代码显得冗余,逻辑又难以理解,在使用lambda表达式时,又要切记:必要时要移除你之前注册过的event handler,以免它们被多次调用,这会使得对代理的声明变得复杂,让代码书写更费事。

QueryTask queryTask = new QueryTask
    ("http://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer/3");
 
// 使用内联Lambda表达式来处理执行成功事件queryTask.ExecuteCompleted += (obj, queryEventArgs) =>
{
    // Do something with results...
    GraphicsLayer graphicsLayer = MyMap.Layers["MyGraphics"] as GraphicsLayer;
    graphicsLayer.Graphics.AddRange(queryEventArgs.FeatureSet.Features);
};
 
// 使用内联Lambda表达式来处理执行失败事件
queryTask.Failed += (obj, taskFailedeventArgs) =>
{
    if (taskFailedeventArgs.Error != null)
        MessageBox.Show(taskFailedeventArgs.Error.Message);
};
 
//在声明了内联的event handler之后调用ExecuteAsync方法 queryTask.ExecuteAsync(new Query()
{
    Where = "1=1",
    ReturnGeometry = true,
    OutSpatialReference = MyMap.SpatialReference
});

 

第二个例子使用新的QueryTask.ExecuteTaskAsync方法,它返回一个“awaitable”任务,其Result属性包含了一个QueryResult实例,返回Task<QueryResult>类型的参数。使用“await”关键字可以调用异步方法,并使得代码暂停执行直到异步任务执行完成返回结果。这种方式的妙处之一,就是看起来代码是顺序执行的,大大增强了代码的可读性。记住,任务执行失败时会抛出异常而不是触发“failed”事件,因此,在合适的地方使用try/catch语句非常重要。

QueryTask queryTask = new QueryTask
    ("http://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer/3");
 
try
{
    //使用await关键字来调用ExecuteTaskAsync
    QueryResult queryResult = await queryTask.ExecuteTaskAsync(new Query()
    {
        Where = "1=1",
        ReturnGeometry = true,
        OutSpatialReference = MyMap.SpatialReference
    });
 
    // Do something with results...
    GraphicsLayer graphicsLayer = MyMap.Layers["MyGraphics"] as GraphicsLayer;
    graphicsLayer.Graphics.AddRange(queryResult.FeatureSet.Features);
}
catch (Exception ex)
{
 // Handle exception
}

 

在WPF SDK 10.2版本中,异步处理支持基于事件( event-based)和基于任务(Task-based)两种模型,但在新的.Net SDK中只支持基于任务的模型,因此WPF开发者在异步处理的时候采用任务模型不仅可以简化代码,还可以非常方便的进行项目迁移。

 

3、使用“using”指令而不是完全限定的命名空间

这是一个简单的小提示,也许你早就开始这么做了,但是它的确值得注意,它会节省你很多时间。新的Windows Desktop API的许多类型与现有的WPF API中的类型具有相同的类名,但是它们使用不同的命名空间,因此,使用using指令可以去掉ESRI.ArcGIS.Client.*程序集,而加上Esri.ArcGISRuntime.*程序集,这样,迁移之后更新一下命名空间,重新编译一下代码即可。在现实中,这两个API中会有各种差异,使得你的代码必须经过适当的修改才能编译成功,但采用这个建议肯定能大幅提高你代码迁移的速度。更新信息请参考usingDirective (C# Reference)

在您的代码中,只要有可能,我们强烈推荐你避免使用完全限定的命名空间而使用using指令,如:

using ESRI.ArcGIS.Client.Tasks;
namespace MyNamespace
{
    public partial class MainWindow : Window
    {
        QueryTask myQueryTask = new QueryTask();
        …
    }
}

当项目需要迁移到新的WindowsDesktop API中时,你只需要简单的修改命名空间即可:

using Esri.ArcGISRuntime.Tasks.Query;
namespace MyNamespace
{
    public partial class MainWindow : Window
    {
        QueryTask myQueryTask = new QueryTask();
        …
    }
}

 

如果您正在计划将一个WPFSDK开发的项目迁移到新的.Net SDK中的话,使用上面3个小技巧能够使得你迁移更加容易,迁移后的代码更加工整,新的SDK已经发布,我们诚恳的期待您花费一点时间来试用一下,相信它能带给你更好的开发体验。

拥抱新的.Net开发框架,WPF开发者如何向.Net迁移

上一篇:Kinect for Windows SDK v2.0 开发笔记 (十七) 深度帧3D


下一篇:Kinect for Windows SDK v2.0 开发笔记 (十六) SDK2.0正式发布 与 自带工具