WebGIS实现要素在线编辑之Silverlight调用FeatureService实现编辑功能

时间:2022-09-29 17:09:51

      在本文中,实现对污染源数据的管理主要是通过FeatureService,FeatureService支持在线的地理要素编辑,并且可以将要素编辑的结果更新至后台的数据库中。在本文中,通过将之前新建的污染源数据库点要素添加到MXD文档中,然后将其发布成FeatureService(具体如何发布请看另一篇博文——http://www.cnblogs.com/potential/archive/2012/11/03/2752796.html)。

      在ArcGIS API for Silverlight中,提供了的EditorWidget工具,通过该工具即可实现对ArcSDE中地理要素的访问并进行相关的编辑。

      ArcGIS API for Silverlight中提供的EditorWidget工具包含了要素属性的编辑,要素形状的编辑,要素选中要素,删除要素等。下面就来看一下具体过程。

      新建一个项目:    

WebGIS实现要素在线编辑之Silverlight调用FeatureService实现编辑功能

项目浏览:

WebGIS实现要素在线编辑之Silverlight调用FeatureService实现编辑功能

之后我们在Expression Blend中编辑界面。大致设计如下:

WebGIS实现要素在线编辑之Silverlight调用FeatureService实现编辑功能

基本控件列表:

WebGIS实现要素在线编辑之Silverlight调用FeatureService实现编辑功能

这里我们声明了一个EditorWidget以及一个FeatureDataForm。我们主要用EditorWidget来实现要素的添加和删除,而用FeatureDataForm来实现要素属性的编辑。注意:EditorWidget本身也具有编辑要素属性的功能。FeatureDataForm同样支持更新数据到数据库,但是他只能修改已有的要素,不能执行添加要素的功能,一般用来编辑某一要素的属性或者显示某一要素的属性信息。

在建立好基本的界面之后,下面开始正式的工作:

1. 我们需要添加一个供我们编辑的要素图层:FeatureLayer.在上一篇中已经讲了如何发布要素服务,这里我们引用上一篇发布的要素服务。示例代码如下:

<esri:Map x:Name="MyMap" Background="White" WrapAround="True" Grid.RowSpan="2">
            <!--底图图层-->
            <esri:ArcGISTiledMapServiceLayer Url="http://www.arcgisonline.cn/ArcGIS/rest/services/ChinaOnlineStreetWarm/MapServer"/>
            <!--需要编辑的要素图层-->
            <esri:FeatureLayer ID="SourceLayer" DisableClientCaching="True" 
                               AutoSave="False"
                               OutFields="*"
                               Mode="OnDemand"
                               Url="http://qzj-pc/ArcGIS/rest/services/RiverSourceMap/FeatureServer/0"/>
        </esri:Map>

以上我们添加了两个图层,一个是底图图层,一个是我们要编辑的要素图层。同时我们这里对要素图层进行了相关的设置。下面对FeatureLayer重要的属性进行一下说明:

OutFields: OutFields类型是一个字符串数组,表示该图层的要素暴露那些字段(属性),也就是说用户可见的属性有哪些。比如上一篇我们定义了一个点要素,并添加了一系列的属性,如排放量,负责人,运行状态,经纬度等,而我现在并不想将这些信息展示给客户端,不想这些信息都被用户看见,那么我们通过设置这里的OutFields暴露的字段来实现。

AutoSave:表示是否自动保存图层要素更改的信息。

Url:表示该要素图层的地址,比如上一篇我们介绍了如何发布FeatureService,这里你就可以将地址修改为你自己发布的FeatureService地址。

2. 设置EditorWidget属性。

示例代码如下:

<esri:EditorWidget HorizontalAlignment="Left" 
                           Margin="20,20,0,0" 
                           Grid.Row="1" 
                           VerticalAlignment="Top" 
                           Background="{StaticResource Brush1}"
                           Map="{Binding ElementName=MyMap}"
                           AutoSelect="False"
                           AlwaysDisplayDefaultTemplates="True"
                           GeometryServiceUrl="http://qzj-pc/ArcGIS/rest/services/Geometry/GeometryServer"
                           ShowAttributesOnAdd="False"/>

EditorWidget重要属性的说明:

Map:表示EditorWidget编辑对应的地图是那个地图,绑定之后我们只能编辑指定地图中的要素图层。

AutoSelect:表示是否自动选择要素。

AlwaysDisplayDefaultTemplates:表示是否显示默认的模版。

ShowAttributesOnAdd:表示在添加要素时是否显示其属性。

GeometryServiceUrl:表示几何服务的地址,该几何服务将用于要素的编辑,例如移动要素,编辑多变的形状等。

LayerIDs:指定该编辑工具具体要编辑那几个要素图层,这些要素图层必须位置Map绑定的地图中,LayerIDs是一个字符串数组类型,不能在xaml中指定其属性值,只能在后台代码中指定。

3.设置FeatureDataForm的相关属性

示例代码如下:

<esri:FeatureDataForm HorizontalAlignment="Right" 
                              Grid.Row="1" 
                              VerticalAlignment="Bottom" 
                              Margin="0,0,20,20"
Visibility="Collapsed"
Background="{StaticResource Brush1}" x:Name="MyFeatureDataForm" FeatureLayer="{Binding Path=Layers[SourceLayer], ElementName=MyMap}" IsReadOnly="False" LabelPosition="Left"/>

FeatureDataForm重要属性的说明:

FeatureLayer:指定该FeatureDataForm是要显示那一个要素图层的信息(也就是被显示的要素位于那个FeatureLayer中)当被显示的要素来自于不同的要素图层时,不用在此绑定,可在后台代码中动态的指定。这里我们默认设置初始时不可见。

完成了对基本控件的属性设置后,我们开始在后台代码中编写相关的控制代码。

最后的XAML中的代码应该是这样的:

<UserControl
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:esri="http://schemas.esri.com/arcgis/client/2009" 
    x:Class="FeatureServiceTest.MainPage"
    mc:Ignorable="d"
    d:DesignHeight="357" d:DesignWidth="508">
    <UserControl.Resources>
        <LinearGradientBrush x:Key="Brush1" EndPoint="1.009,0.82" StartPoint="0.001,0.039">
            <GradientStop Color="#1970A14A" Offset="0"/>
            <GradientStop Color="#994795A9"/>
            <GradientStop Color="#7F859797"/>
            <GradientStop Color="#663EA4B8"/>
            <GradientStop Color="#CC296F81" Offset="0.59"/>
            <GradientStop Color="#B299A7A3" Offset="1"/>
            <GradientStop Color="#72B2D8CB"/>
            <GradientStop Color="#7F5FB4A7" Offset="0.262"/>
        </LinearGradientBrush>
    </UserControl.Resources>

    <Grid x:Name="LayoutRoot" Background="White">
        <Grid.RowDefinitions>
            <RowDefinition Height="0.193*"/>
            <RowDefinition Height="0.807*"/>
        </Grid.RowDefinitions>
        <!--Map控件-->
        <esri:Map Background="White" WrapAround="True" Grid.RowSpan="2" x:Name="MyMap">
            <!--地图图层-->
            <esri:ArcGISTiledMapServiceLayer Url="http://www.arcgisonline.cn/ArcGIS/rest/services/ChinaOnlineStreetWarm/MapServer"/>
            <!--需要编辑的要素图层-->
            <esri:FeatureLayer ID="SourceLayer" DisableClientCaching="True" 
                               AutoSave="False"
                               OutFields="*"
                               Mode="OnDemand"
                               Url="http://qzj-pc/ArcGIS/rest/services/RiverSourceMap/FeatureServer/0"/>
        </esri:Map>
        <!--标题的背景框-->
        <Rectangle Fill="{StaticResource Brush1}">
            <Rectangle.Effect>
                <DropShadowEffect/>
            </Rectangle.Effect>
        </Rectangle>
        <!--标题-->
        <TextBlock TextWrapping="Wrap" Text="要素在线编辑" FontSize="48" VerticalAlignment="Center" Foreground="#FF1A1717" Margin="50,0,0,0">
            <TextBlock.Effect>
                <DropShadowEffect/>
            </TextBlock.Effect>
        </TextBlock>
        <!--要素编辑的控件-->
        <esri:EditorWidget x:Name="MyEditorWidget"
HorizontalAlignment="Left" Margin="20,20,0,0" Grid.Row="1" VerticalAlignment="Top" Background="{StaticResource Brush1}" Map="{Binding ElementName=MyMap}" AutoSelect="False" AlwaysDisplayDefaultTemplates="True" GeometryServiceUrl="http://qzj-pc/ArcGIS/rest/services/Geometry/GeometryServer" ShowAttributesOnAdd="False"/> <!--显示要素属性以及编辑属性的FeatureDataForm--> <esri:FeatureDataForm HorizontalAlignment="Right" Grid.Row="1" VerticalAlignment="Bottom" Margin="0,0,20,20"
Visibility="Collapsed"
Background="{StaticResource Brush1}" x:Name="MyFeatureDataForm" FeatureLayer="{Binding Path=Layers[SourceLayer], ElementName=MyMap}" IsReadOnly="False" LabelPosition="Left"/> </Grid> </UserControl>

4.Coding Behind

首先我们注册以下几个事件:

EditorWidget控件:Loaded事件(必选)

FeatureDataForm控件:EditEnded事件(可选,我们想在编辑完成时关闭FeatureDataForm)

FeatureLayer图层:MouseLeftButtonDown事件(可选,这里我们想实现点击某一要素时,显示其具体信息)

注意:这里不建议在XAML代码中注册事件,最好将注册事件和xaml代码分离。

我们在MainPage.xaml.cs的MainPage()构造函数中注册以上的事件:

这时我们的后台代码如下所示,我们还没有添加相关的事件操作。

using System;
using System.Windows;
using System.Windows.Controls;
using ESRI.ArcGIS.Client;
namespace FeatureServiceTest
{
    public partial class MainPage : UserControl
    {
        //声明一个FeatureLayer变量,用来获取编辑的要素图层
        private FeatureLayer MyFeatureLayer;
        public MainPage()
        {
            InitializeComponent();
            //将Map中的SourceLayer要素图层赋给MyFeatureLayer。
            MyFeatureLayer = MyMap.Layers["SourceLayer"] as FeatureLayer;
            //注册要素图层MouseLeftButtonDown事件
            MyFeatureLayer.MouseLeftButtonDown += FeatureLayer_MouseLeftButtonDown;
            //注册EditorWidget的Loaded事件
            MyEditorWidget.Loaded += EditorWidget_Loaded;
            //注册FeatureDataForm的EditEnded事件
            MyFeatureDataForm.EditEnded += MyFeatureDataForm_EditEnded; 
        }

        private void MyFeatureDataForm_EditEnded(object sender, EventArgs e)
        {

        }

        private void EditorWidget_Loaded(object sender, RoutedEventArgs e)
        {

        }

        private void FeatureLayer_MouseLeftButtonDown(object sender, ESRI.ArcGIS.Client.GraphicMouseButtonEventArgs e)
        {

        }
    }
}

接下来需要完成的工作是:

1.在EditorWidget_Loaded方法中指定EditorWidget编辑的要素图层

  private void EditorWidget_Loaded(object sender, RoutedEventArgs e)
        {
            string[] layerIDs = {"SourceLayer"};
            MyEditorWidget.LayerIDs = layerIDs;
        }

2.在FeatureLayer_MouseLeftButtonDown方法中添加相应的处理代码

这里需要实现的方法是:点击不同的要素(点要素),则显示其相应的属性信息。这里我们只需要将FeatureDataForm的GraphicSource属性绑定到我们点击的Graphic即可。示例代码如下:

 private void FeatureLayer_MouseLeftButtonDown(object sender, ESRI.ArcGIS.Client.GraphicMouseButtonEventArgs e)
        {
            FeatureLayer featureLayer = sender as FeatureLayer;

            foreach (Graphic g in featureLayer.Graphics)
                if (g.Selected)
                    g.UnSelect();

            e.Graphic.Select();
            MyFeatureDataForm.GraphicSource = e.Graphic;
            MyFeatureDataForm.Visibility = Visibility.Visible;
        }

在上一篇中我们建立的点要素包含了经纬度信息,这里我们想在添加点要素时根据其在地图上的位置来自动设置其经纬度属性。

现在我们声明一个类级别的变量:

private static ESRI.ArcGIS.Client.Projection.WebMercator _mercator =
        new ESRI.ArcGIS.Client.Projection.WebMercator();

WebMercator变量的作用可用于坐标系之间的相互转换,它具有两个方法:


FromGeographic:将几何要素的坐标系从4326坐标系转换到102100坐标系

ToGeographic:将几何要素的坐标系从102100坐标系转换到4326坐标系

此外每一个点要素实际上也是一个MapPoint,MapPoint具有X,Y属性,在102100坐标系中是以米为单位表示点的坐标。因此通过将点要素转化为MapPoint,然后通过ToGeographic方法转化成4326坐标系下的点,然后再获得其X,Y,即可得相应的经纬度。最后赋给点要素的经纬度属性。示例代码如下:

//将120010坐标系,转换为4326下的坐标系
            MapPoint mapPoint = _mercator.ToGeographic(e.Graphic.Geometry) as MapPoint;
            //自动的添加 经纬度
            e.Graphic.Attributes["Longitude"] = mapPoint.X;
           
e.Graphic.Attributes[
"Latitude"] = mapPoint.Y;

 

3.在MyFeatureDataForm_EditEnded中添加退出编辑代码,即关闭FeatureDataForm,并清空其数据源。

  private void MyFeatureDataForm_EditEnded(object sender, EventArgs e)
        {
            MyFeatureDataForm.GraphicSource = null;
            MyFeatureDataForm.Visibility = Visibility.Collapsed;
        }


这样所有的工作便已经完成,此时后台的代码应该如下所示:

using System;
using System.Windows;
using System.Windows.Controls;
using ESRI.ArcGIS.Client;
using ESRI.ArcGIS.Client.Geometry;

namespace FeatureServiceTest
{
    public partial class MainPage : UserControl
    {
        ESRI.ArcGIS.Client.Projection.WebMercator _mercator =
       new ESRI.ArcGIS.Client.Projection.WebMercator();
        //声明一个FeatureLayer变量,用来获取编辑的要素图层
        private FeatureLayer MyFeatureLayer;
        public MainPage()
        {
            InitializeComponent();
            //将Map中的SourceLayer要素图层赋给MyFeatureLayer。
            MyFeatureLayer = MyMap.Layers["SourceLayer"] as FeatureLayer;
            //注册要素图层MouseLeftButtonDown事件
            MyFeatureLayer.MouseLeftButtonDown += FeatureLayer_MouseLeftButtonDown;
            //注册EditorWidget的Loaded事件
            MyEditorWidget.Loaded += EditorWidget_Loaded;
            //注册FeatureDataForm的EditEnded事件
            MyFeatureDataForm.EditEnded += MyFeatureDataForm_EditEnded; 
        }

        private void MyFeatureDataForm_EditEnded(object sender, EventArgs e)
        {
            MyFeatureDataForm.GraphicSource = null;
            MyFeatureDataForm.Visibility = Visibility.Collapsed;
        }

        private void EditorWidget_Loaded(object sender, RoutedEventArgs e)
        {
            string[] layerIDs = {"SourceLayer"};
            MyEditorWidget.LayerIDs = layerIDs;
        }

        private void FeatureLayer_MouseLeftButtonDown(object sender, ESRI.ArcGIS.Client.GraphicMouseButtonEventArgs e)
        {
            FeatureLayer featureLayer = sender as FeatureLayer;

            foreach (Graphic g in featureLayer.Graphics)
                if (g.Selected)
                    g.UnSelect();

            e.Graphic.Select();
         
            //将120010坐标系,转换为4326下的坐标系
            MapPoint mapPoint = _mercator.ToGeographic(e.Graphic.Geometry) as MapPoint;
            //自动的添加 经纬度
              e.Graphic.Attributes["Longitude"] = mapPoint.X;
            e.Graphic.Attributes["Latitude"] = mapPoint.Y;

            MyFeatureDataForm.GraphicSource = e.Graphic;
            MyFeatureDataForm.Visibility = Visibility.Visible;
        }
    }
}

下面来看看运行的效果以及观察是否能够更新编辑到数据库。

点击要素,会自动根据点要素在地图中的坐标为其经纬度属性赋值

WebGIS实现要素在线编辑之Silverlight调用FeatureService实现编辑功能

注意下图:这里运行状态属性栏,我们发现是下拉框,只能选择运行状态和关闭状态。这就是我们在上一篇说的设置属性域起的作用。

WebGIS实现要素在线编辑之Silverlight调用FeatureService实现编辑功能

 

 时间属性只允许我们输入时间。这也是由于我们之前设置对时间属性应用了属性域的原因。

WebGIS实现要素在线编辑之Silverlight调用FeatureService实现编辑功能

WebGIS实现要素在线编辑之Silverlight调用FeatureService实现编辑功能

 最后编辑完成之后点击保存按钮。

WebGIS实现要素在线编辑之Silverlight调用FeatureService实现编辑功能

验证是否保存成功,打开ArcCatalog,浏览到Feature Service使用的地理数据库,打开我们在Feature Service使用的要素属性表,就会发现所以的更改已保存到了数据库。

至此,关于在线要素编辑的讲解已经全部完成。

(版权所有,转载请标明出处)