用ArcGIS Runtime本地服务器实现MVVM



我正在尝试设置用于显示.mpk的ESRI本地服务器。我有一个类似的型号

public class Model
{
private string basemapLayerUri = "http://services.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer";
private string mapPackage = "D:\App\Data\Canada.mpk";
public Model() { }
public string BasemapLayerUri
{
get { return this.basemapLayerUri; }
set
{
if (value != this.basemapLayerUri)
{
this.basemapLayerUri = value;
}
}
}
public string MapPackage
{
get { return this.mapPackage; }
set
{
if (value != this.mapPackage)
{
this.mapPackage = value;
}
}
}
}

ViewModel.cs中,I类具有

public class ViewModel : INotifyPropertyChanged
{
public Model myModel { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
public ViewModel()
{
myModel = new Model();
this.CreateLocalServiceAndDynamicLayer();
}
public string BasemapUri
{
get { return myModel.BasemapLayerUri; }
set
{
this.myModel.BasemapLayerUri = value;
OnPropertyChanged("BasemapUri");
}
}
public async void CreateLocalServiceAndDynamicLayer()
{
LocalMapService localMapService = new LocalMapService(this.MAPKMap);
await localMapService.StartAsync();
ArcGISDynamicMapServiceLayer arcGISDynamicMapServiceLayer = new ArcGISDynamicMapServiceLayer()
{
ID = "mpklayer",
ServiceUri = localMapService.UrlMapService,
};
//myModel.Map.Layers.Add(arcGISDynamicMapServiceLayer);
}
public string MAPKMap
{
get { return myModel.MapPackage; }
set
{
this.myModel.MapPackage = value;
OnPropertyChanged("MAPKMap");
}
}
protected void OnPropertyChanged([CallerMemberName] string member = "")
{
var eventHandler = PropertyChanged;
if (eventHandler != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(member));
}
}
}

正如你所看到的,我正在尝试像一样在ViewModel.cs中实现本地服务器和动态层

public async void CreateLocalServiceAndDynamicLayer()
{
LocalMapService localMapService = new LocalMapService(this.MAPKMap);
await localMapService.StartAsync();
ArcGISDynamicMapServiceLayer arcGISDynamicMapServiceLayer = new ArcGISDynamicMapServiceLayer()
{
ID = "mpklayer",
ServiceUri = localMapService.UrlMapService,
};
//myModel.Map.Layers.Add(arcGISDynamicMapServiceLayer);
}

但是我不知道如何将该服务绑定到CCD_ 4?我试过

myModel.Map.Layers.Add(arcGISDynamicMapServiceLayer);

但正如您所知,myModel没有任何Map对象。

更新

using M_PK2.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using Esri.ArcGISRuntime.LocalServices;
using Esri.ArcGISRuntime.Controls;
using Esri.ArcGISRuntime.Layers;
namespace M_PK2.ViewModels
{
class ViewModel : ViewModelBase
{
private readonly LocalMapService localMapService;
private readonly Model myModel;
private LayerCollection layers;
public ViewModel()
{
myModel = new Model();
layers = new LayerCollection();
localMapService = new LocalMapService(myModel.MapPackage);
starting += onStarting;
starting(this, EventArgs.Empty);
}
private event EventHandler starting = delegate { };
private async void onStarting(object sender, EventArgs args)
{
starting -= onStarting; //optional
// the following runs on background thread
await localMapService.StartAsync();
// returned to the UI thread
var serviceLayer = new ArcGISDynamicMapServiceLayer()
{
ID = "mpklayer",
ServiceUri = localMapService.UrlMapService,
};
Layers.Add(serviceLayer);
OnPropertyChanged(nameof(Layers)); //Notify UI
}

public LayerCollection Layers
{
get
{
return layers;
}
}
}
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged = delegate { };
protected void OnPropertyChanged([CallerMemberName] string member = "")
{
PropertyChanged(this, new PropertyChangedEventArgs(member));
}
}
}

避免使用async void,事件处理程序、除外

参考Async/Await-异步编程的最佳实践

在您的案例中,您混合了视图中的UI关注点。视图模型应该公开视图执行其功能所需的内容。

由于使用的依赖项LocalMapService具有异步性质,因此应该创建一个异步事件处理程序来管理获取服务URI,并在通过绑定属性更改事件完成该任务时通知UI。

例如

public class ViewModel : ViewModelBase {
private readonly LocalMapService localMapService;
private readonly Model myModel;
private string serviceUri;
public ViewModel() {
myModel = new Model();
localMapService = new LocalMapService(myModel.MapPackage);
starting += onStarting;
starting(this, EventArgs.Empty);
}
private event EventHandler starting = delegate { };
private async void onStarting(object sender, EventArgs args) {
starting -= onStarting; //optional
// the following runs on background thread
await localMapService.StartAsync(); 
// returned to the UI thread
ServiceUri = localMapService.UrlMapService; //notifies UI
}
public string ServiceUri {
get { return serviceUri; }
set {
serviceUri = value;
OnPropertyChanged();
}
}
}
public class ViewModelBase : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged = delegate { };
protected void OnPropertyChanged([CallerMemberName] string member = "") {
PropertyChanged(this, new PropertyChangedEventArgs(member));
}
}

这样,在异步启动服务后,UI将收到更改通知。

<!-- Add a MapView Control. -->
<esriControls:MapView x:Name="MapView1">
<!-- Add a Map. -->
<esriControls:Map>
<!-- Add an ArcGISDynamicMapServiceLayer via XAML. -->
<esriLayers:ArcGISDynamicMapServiceLayer ID="mpklayer" 
ServiceUri="{Bind ServiceUri}"/>
</esriControls:Map>
</esriControls:MapView>

如果目标是能够操作多个图层,那么我建议绑定到Map.layers属性,以便能够直接访问视图模型中的图层集合。

视图模型最终可能看起来像

public class ViewModel : ViewModelBase {
private readonly LocalMapService localMapService;
private readonly Model myModel;
private LayerCollection layers;
public ViewModel() {
myModel = new Model();
layers = new LayerCollection();
localMapService = new LocalMapService(myModel.MapPackage);
starting += onStarting;
starting(this, EventArgs.Empty);
}
private event EventHandler starting = delegate { };
private async void onStarting(object sender, EventArgs args) {
starting -= onStarting; //optional
// the following runs on background thread
await localMapService.StartAsync(); 
// returned to the UI thread
var serviceLayer = new ArcGISDynamicMapServiceLayer() {
ID = "mpklayer",
ServiceUri = localMapService.UrlMapService,
};
Layers.Add(serviceLayer);
}
public LayerCollection Layers {
get {
return layers;
}
}
}

和视图

<!-- Add a MapView Control. -->
<esriControls:MapView x:Name="MapView1">
<!-- Add a Map. with layers via binding-->
<esriControls:Map Layers="{Bind Layers, Mode=OneWay}" />
</esriControls:MapView>

您现在可以根据需要通过代码操作图层

我没有可用的SDK,但以下代码应该可以使用:

视图模型:

private readonly LocalMapService localMapService;
// initialize localMapService instance in the constructor 
public string UrlMapService
{
get { return localMapService.UrlMapService; }
}

XAML:

<!-- A Map ControlView to display various GIS layers. -->
<esriControls:MapView x:Name="MapView1" Width="448" Height="480" VerticalAlignment="Top" Margin="2,2,2,2">
<!-- A Map. -->
<esriControls:Map  x:Name="Map1" >
<!-- Add an ArcGISDynamicMapServiceLayer via Xaml. Set the ID and ImageFormat properties. -->
<esriLayers:ArcGISDynamicMapServiceLayer ID="serviceLayer" ImageFormat="PNG24" 
ServiceUri="{Binding UrlMapService, Mode=OneWay}"/>
</esriControls:Map>
</esriControls:MapView>

最新更新