zoukankan      html  css  js  c++  java
  • ArcGIS API for Silverlight开发入门(2):一个基础地图实例<转>

       这节在一个地图实例的基础上,来对Silverlight API中的一些基本概念做一个总体了解,顺便熟悉一下Silverlight的开发知识。
            点击这里,直接看效果。

    extendedmap.png
            根据上一节的知识,可以知道这个Silverlight程序里包含了一个Map控件,并且里面至少有一个WorldImagery的图层。那么Page.xaml里的关键代码开起来应该是这样的:
    1. <Grid x:Name="LayoutRoot">
    2. <esri:Map x:Name="Map1">
    3. <esri:Map.Layers>
    4. <esri:ArcGISTiledMapServiceLayer ID="WorldImageLayer" x:Name="WorldImageLayer" Initialized="WorldImageLayer_Initialized"
    5. Url="http://services.arcgisonline.com/ArcGIS/rest/services/ESRI_Imagery_World_2D/MapServer" />
    6. </esri:Map.Layers>
    7. </esri:Map>
    8. </Grid>
    复制代码
    所有的布局工作都在一个Grid中进行,给它起个名字叫LayoutRoot。Grid里面放了一个esri:Map元素(Map控件),它继承自Silverlight的Control,所以拥有Width和Height属性,默认是Auto,自动填充整个Grid。Map.Layers是一个集合,可以往里面添加layer,这里的layer指的是ArcGIS Server或其他软件发布的地图服务,目前SilverlightAPI中支持的能够直接使用的有ArcGISDynamicMapServiceLayer,ArcGISTiledMapServiceLayer,ArcGISImageServiceLayer,分别对应ArcGIS Server发布的动态地图服务,缓存地图服务(两种Map Service)和ImageService,这三种图层是拿来即用的,如果你想加入别的地图服务,比如WMS服务,则需要自己继承相应类型的的Layer;此外还有GraphicsLayer,ElementLayer,SilverlightAPI特有的FeatureLayer等。这些都会在之后的小节中讲到。强调一下,与ADF开发里MapResourceManager一样,在Map中加入的内容实际上是地图服务,但当做一个layer处理。
            下面就对这个例子中的每一部分来做说明(与上图中的序号相对应)。

    1、当地图移动时获取地图范围。
            当地图范围改变后,显示出当前地图范围的边界值。
            这部分的页面布局是这样的:
    1. <Grid x:Name="Gridright" Margin="0,15,20,0" HorizontalAlignment="Right" VerticalAlignment="Stretch">
    2. <!--extent-->
    3. <Canvas Width="215" Height="110" VerticalAlignment="Top">
    4. <Rectangle Style="{StaticResource rectBottom}" />
    5. <Rectangle Style="{StaticResource rectMiddle}" />
    6. <Rectangle Style="{StaticResource rectTop}" />
    7. <TextBlock x:Name="TBextent" Margin="20,15,15,0" Text="范围:" TextWrapping="Wrap" FontWeight="Bold" />
    8. </Canvas>
    9. </Grid>
    复制代码
    有关xaml中详细的布局知识请大家参照其他例子学习,这里稍作讲解。外面的Gridright这个Grid就是页面右边1、2、3、6的父容器,之所以不用StackPanel是因为6需要贴着页面底部,StackPanel中的元素都会flow贴到一起。三个矩形组合便构成了整体轮廓,由于它们都在一个Canvas中,所以会产生压盖效果。最先加入的rectBottom这个矩形便是最底下的阴影效果,中间的矩形是蓝色框,最上面的矩形是白色的文字显示区域。“{ }”里的内容在xaml中称作markupextention,StaticResource是使用在别处已经定义好的资源(resource)来对本元素的一些属性进行自动赋值,这里用来修饰Rectangle的外观。xaml中除了StaticResource这种markupextention之外还有Binding和TemplateBinding两种markup extention,分别用于数据绑定(databinding)和自定义control的外观。上面的StaticResource是在App.xaml中定义的,这样就可以在本工程的任何页面中使用,当然也可以定义为LayoutRoot这个Grid的Resource。贴出来大家一看就明白了:
    1.         <Application.Resources>
    2.         <Style x:Key="rectBottom" TargetType="Rectangle">
    3.             <Setter Property="RadiusX" Value="10" />
    4.             <Setter Property="RadiusY" Value="10" />
    5.             <Setter Property="Fill" Value="#22000000" />
    6.             <Setter Property="Canvas.Left" Value="5" />
    7.             <Setter Property="Canvas.Top" Value="5" />
    8.             <Setter Property="Width" Value="215" />
    9.             <Setter Property="Height" Value="110" />
    10.         </Style>
    11.         <Style x:Key="rectMiddle" TargetType="Rectangle">
    12.             <Setter Property="RadiusX" Value="10" />
    13.             <Setter Property="RadiusY" Value="10" />
    14.             <Setter Property="Fill" Value="#775C90B2" />
    15.             <Setter Property="Canvas.Left" Value="0" />
    16.             <Setter Property="Canvas.Top" Value="0" />
    17.             <Setter Property="Width" Value="215" />
    18.             <Setter Property="Height" Value="110" />
    19.             <Setter Property="Stroke" Value="Gray" />
    20.         </Style>
    21.         <Style x:Key="rectTop" TargetType="Rectangle">
    22.             <Setter Property="RadiusX" Value="5" />
    23.             <Setter Property="RadiusY" Value="5" />
    24.             <Setter Property="Fill" Value="#FFFFFFFF" />
    25.             <Setter Property="Canvas.Left" Value="10" />
    26.             <Setter Property="Canvas.Top" Value="10" />
    27.             <Setter Property="Width" Value="195" />
    28.             <Setter Property="Height" Value="90" />
    29.             <Setter Property="Stroke" Value="DarkGreen" />
    30.         </Style>
    31.     </Application.Resources>
    复制代码
    它们就相当于网页中的css。如果不使用StaticResource,那么三个矩形看起来应该是这样的:
    1. <Rectangle RadiusX="10" RadiusY="10" Fill="#22000000" Canvas.Left="5" Canvas.Top="5" Width="215" Height="110" />
    2. <Rectangle RadiusX="10" RadiusY="10" Fill="#775C90B2" Canvas.Left="0" Canvas.Top="0" Width="215" Height="110" Stroke="Gray" />
    3. <Rectangle RadiusX="5" RadiusY="5" Fill="#FFFFFFFF" Canvas.Left="10" Canvas.Top="10" Width="195" Height="90" Stroke="DarkGreen" />
    复制代码
    你猜的没错,在其他矩形框部分也使用到了这些属性。通过实践可以感受到,xaml中的布局在一般使用中比html+css的布局要简单和灵活许多。好了,继续。
            Map控件里面已经封装了一些事件来供我们使用,我们可以在需要的时候捕获它们来进行处理。如果做过ArcGIS产品的二次开发,你应该已经想到我们要捕获的就是Map的ExtentChanged事件;而要在地图移动或者缩放的过程中也实时显示地图范围,则还要对ExtentChanging事件做处理。细心的你可能已经发现,在上面的xaml代码中已经对世界地图这个图层的Initialized事件添加了一个hanlder:WorldImageLayer_Initialized。当然可以像这样一样给Map的这两个事件添加handler,但这里并不这么做,而是在世界地图图层的Initialized事件里来绑定它们(移动地图时出发ExtentChanged事件,网速过慢导致图层并未加入到Map中,则会报错)。来看看Page.xaml.cs中的code-behind代码:
    1. private void WorldImageLayer_Initialized(object sender, EventArgs e)
    2. {
    3. Map1.ExtentChanged += new EventHandler<ESRI.ArcGIS.ExtentEventArgs>(Map1_ExtentChange);
    4. Map1.ExtentChanging += new EventHandler<ESRI.ArcGIS.ExtentEventArgs>(Map1_ExtentChange);
    5. }
    复制代码
    没错,把两个事件绑定到同一个handler即可。再看看Map1_ExtentChange中的代码:
    1. private void Map1_ExtentChange(object sender, ESRI.ArcGIS.ExtentEventArgs e)
    2. {
    3. TBextent.Text = string.Format("地图范围:\nMinX:{0}\nMinY:{1}\nMaxX:{2}\nMaxY:{3}",
    4. e.NewExtent.XMin, e.NewExtent.YMin, e.NewExtent.XMax, e.NewExtent.YMax);
    5. }
    复制代码
    很简单吧?顺便提一下,ExtentEventArgs里既然有NewExtent,当然就有OldExtent了,通过比较这两个变量就可以分析出当前进行的是放大、缩小还是平移操作了。其实还有个更简单的办法,查查看Map的Resolution属性吧。
    对于Silverlight API中内容,是不是感觉很容易呢(当然你得做够xaml的功课才行)?那么赶快来看第二部分。

    2、当鼠标移动时获取鼠标坐标。
            包括屏幕坐标和地图坐标。外观样式方面是这样的:
    1. <!--mouse coords-->
    2. <Canvas Width="215" Height="110" Margin="0,120,0,0" VerticalAlignment="Top">
    3. <Rectangle Style="{StaticResource rectBottom}" />
    4. <Rectangle Style="{StaticResource rectMiddle}" />
    5. <Rectangle Style="{StaticResource rectTop}" />
    6. <StackPanel Orientation="Vertical" Margin="20,15,15,0">
    7. <TextBlock x:Name="TBscreencoords"
    8. HorizontalAlignment="Left" VerticalAlignment="Center" Text="屏幕坐标:" TextWrapping="Wrap" FontWeight="Bold" />
    9. <TextBlock x:Name="TBmapcoords"
    10. HorizontalAlignment="Left" VerticalAlignment="Center" Text="地图坐标:" TextWrapping="Wrap" FontWeight="Bold" />
    11. </StackPanel>
    12. </Canvas>
    复制代码
    那么接下来要捕捉那个事件呢?当然就是MouseMove啦。不过如果查看SilverlightAPI中的Map类,发现并没有这个事件。但要记住Map是继承自xaml中的Control,Control继承自FrameworkElement,FrameworkElement继承自UIElement,这里就有一个MouseMove事件了。所以Map控件的MouseMove是xaml中而不是Siverlight API中的事件(当然整个SilverlightAPI都是建立在xaml基础上的)。在esri:Map标签中添加一个MouseMove事件(MouseMove="Map1_MouseMove"),来看看code-behind代码:
    1. private void Map1_MouseMove(object sender, MouseEventArgs e)
    2. {
    3. if (Map1.Extent != null)
    4. {
    5. System.Windows.Point screenPnt = e.GetPosition(Map1);
    6. TBscreencoords.Text = string.Format("屏幕坐标:\nX:{0},Y:{1}", screenPnt.X, screenPnt.Y);

    7. ESRI.ArcGIS.Geometry.MapPoint mapPnt = Map1.ScreenToMap(screenPnt);
    8. TBmapcoords.Text = string.Format("地图坐标:\nX:{0}\nY:{1}", Math.Round(mapPnt.X, 4), Math.Round(mapPnt.Y, 4));
    9. }
    10. }
    复制代码
    可以看到Map控件提供了屏幕与地图坐标之间转换的方法,好比开发人员的一座桥梁,用来往返于Silverlight特性与地图之间,非常方便。需要说明的是,这里GetPosition(Map1)获得的屏幕坐标是相对于Map控件的,而不是显示器的左上角。ok,继续来看第三部分。

    3、Map里的动画效果。
            当地图放大和平移时都可以看到平滑的效果,这归功于Silverlight的动画功能。Map在封装完动画效果后,给了我们两个属性来对它们进行设置:PanDuration和ZoomDuration,用于设置这两个动作持续的时间。它们都是TimeSpan类型的变量,合理的设置可以带来良好的用户体验。看看这部分的布局:
    1. <!--map animation slider-->
    2. <Canvas Width="215" Height="130" Margin="0,240,0,0" VerticalAlignment="Top">
    3. <Rectangle Style="{StaticResource rectBottom}" Height="130" />
    4. <Rectangle Style="{StaticResource rectMiddle}" Height="130" />
    5. <Rectangle Style="{StaticResource rectTop}" Height="110" />
    6. <StackPanel Orientation="Vertical" Margin="20,15,15,0">
    7. <TextBlock HorizontalAlignment="Left" Text="设置地图缩放动作持续时间:" TextWrapping="Wrap" FontWeight="Bold" />
    8. <TextBlock x:Name="TBzoomdurationvalue" HorizontalAlignment="Left" Text="当前值:" TextWrapping="Wrap" FontWeight="Bold" />
    9. <Slider x:Name="sliderzoomanimation" Orientation="Horizontal" Minimum="0" Maximum="20" SmallChange="1"
    10. LargeChange="5" Cursor="Hand" ValueChanged="slideranimation_ValueChanged" Width="180" />
    11. <TextBlock HorizontalAlignment="Left" Text="设置地图平移动作持续时间:" TextWrapping="Wrap" FontWeight="Bold" />
    12. <TextBlock x:Name="TBpandurationvalue" HorizontalAlignment="Left" Text="当前值:" TextWrapping="Wrap" FontWeight="Bold" />
    13. <Slider x:Name="sliderpananimation" Orientation="Horizontal" Minimum="0" Maximum="20" SmallChange="1"
    14. LargeChange="5" Cursor="Hand" ValueChanged="slideranimation_ValueChanged" Width="180" />
    15. </StackPanel>
    16. </Canvas>
    复制代码
    主要用到了两个slider控件。再看看拖动滑块时的事件代码,为了省事,这两个事件也用了同一个handler:
    1. private void slideranimation_ValueChanged(object sender, RoutedPropertyChangedEventArgs e)
    2. {
    3. Slider s=sender as Slider;
    4. if (s.Name == "sliderzoomanimation")
    5. {
    6. Map1.ZoomDuration = new TimeSpan(0, 0, Convert.ToInt32(sliderzoomanimation.Value));
    7. TBzoomdurationvalue.Text = string.Format("当前值:{0}秒", Convert.ToInt32(sliderzoomanimation.Value));
    8. }
    9. else
    10. {
    11. Map1.PanDuration = new TimeSpan(0, 0, Convert.ToInt32(sliderpananimation.Value));
    12. TBpandurationvalue.Text = string.Format("当前值:{0}秒", Convert.ToInt32(sliderpananimation.Value));
    13. }
    14. }
    复制代码
    对应着地图效果,应该很容易理解。继续第四部分。

    4、对地图服务可见性与动态地图服务中图层可见性的控制。
            还是要强调一下,WorldImagery和StreetMap两个能看到的地图实际上都是地图服务,当作layer加入到了Map控件中;而动态地图服务USA中的图层Cities,Rivers,States才是与ArcMap中图层相对的概念。对于WorldImagery和StreetMap之间的切换,主要用到了Silverlight API里Layer的
    Visible属性;而动态服务中图层可见性的操作,主要是对ArcGISDynamicMapServiceLayer的VisibleLayers数组做了设置。
            StreetMap这个服务其实一开始就加入了地图(在esri:Map标签中):
    1. <esri:ArcGISTiledMapServiceLayer ID="StreetMapLayer"
    2. Url="http://services.arcgisonline.com/ArcGIS/rest/services/ESRI_StreetMap_World_2D/MapServer" Visible="False" />
    复制代码
    而设置了Visible="False"。图层不可见时地图不会对它做任何处理,所以不用担心会耗费流量或加重程序负担。
            看看布局部分:
    1. <StackPanel HorizontalAlignment="Left" Margin="20,15,0,0">
    2. <Canvas x:Name="Canvasleft" Width="165" Height="90" HorizontalAlignment="Left" VerticalAlignment="Top">
    3. <Rectangle Style="{StaticResource rectBottom}" Width="165" Height="90" />
    4. <Rectangle Style="{StaticResource rectMiddle}" Fill="#7758FF00" Width="165" Height="90" />
    5. <Rectangle Style="{StaticResource rectTop}" Width="145" Height="70" />
    6. <!--change layer-->
    7. <StackPanel Margin="20,15,15,0">
    8. <TextBlock Text="切换图层:" TextWrapping="Wrap" FontWeight="Bold" />
    9. <StackPanel Orientation="Horizontal">
    10. <ToggleButton x:Name="TBimagery" Content="Imagery" Click="TBimagery_Clicked" Cursor="Hand" />
    11. <ToggleButton x:Name="TBstreetmap" Content="StreetMap" Click="TBstreetmap_Clicked" Cursor="Hand" />
    12. </StackPanel>
    13. <CheckBox Margin="0,5,0,0" x:Name="chkboxDynamicLayer" Content="添加一个动态图层吧" IsChecked="False" Click="chkboxDynamicLayer_Click" Cursor="Hand" />
    14. </StackPanel>
    15. </Canvas>
    16. </StackPanel>
    复制代码
    这里使用了ToggleButton,CheckBox和RadioButton都由它派生而来。Silverlight2中的ToggleButton不能设置Group(一个Group中自动限定同时只能有一个控件处于激活状态),不如Flex里的ToggleButton来的方便,所以code-behind中多做了些工作。当然这里使用RadioButton也是可以的。
    1. private void TBimagery_Clicked(object sender, RoutedEventArgs e)
    2. {
    3. if (TBstreetmap.IsChecked==true)
    4. {
    5. Map1.Layers["WorldImageLayer"].Visible = true;
    6. Map1.Layers["WorldImageLayer"].Opacity = 0;
    7. TBstreetmap.IsChecked = false;
    8. Storyboard sbworldmapshow = makestoryboard("WorldImageLayer", 0, 1);
    9. Storyboard sbstreetmaphide = makestoryboard("StreetMapLayer", 1, 0);
    10. sbworldmapshow.Begin();
    11. sbstreetmaphide.Begin();
    12. hidelayername = "StreetMapLayer";
    13. timer.Begin();
    14. }
    15. TBimagery.IsChecked = true;
    16. }

    17. private void TBstreetmap_Clicked(object sender, RoutedEventArgs e)
    18. {
    19. if (TBimagery.IsChecked==true)
    20. {
    21. Map1.Layers["StreetMapLayer"].Visible = true;
    22. Map1.Layers["StreetMapLayer"].Opacity = 0;
    23. TBimagery.IsChecked = false;
    24. Storyboard sbstreetmapshow = makestoryboard("StreetMapLayer", 0, 1);
    25. Storyboard sbworldmaphide = makestoryboard("WorldImageLayer", 1, 0);
    26. sbstreetmapshow.Begin();
    27. sbworldmaphide.Begin();
    28. hidelayername = "WorldImageLayer";
    29. timer.Begin();
    30. }
    31. TBstreetmap.IsChecked = true;
    32. }

    33. private void timer_Tick(object sender, EventArgs e)
    34. {
    35. Map1.Layers[hidelayername].Visible = false;
    36. }

    37. public Storyboard makestoryboard(string layername, double from, double to)
    38. {
    39. Storyboard sb = new Storyboard();
    40. ESRI.ArcGIS.ArcGISTiledMapServiceLayer layer = Map1.Layers[layername] as ESRI.ArcGIS.ArcGISTiledMapServiceLayer;
    41. DoubleAnimation doubleAnim = new DoubleAnimation();
    42. doubleAnim.Duration = new TimeSpan(0, 0, 5);
    43. doubleAnim.From = from;
    44. doubleAnim.To = to;
    45. Storyboard.SetTarget(doubleAnim, layer);
    46. Storyboard.SetTargetProperty(doubleAnim, new PropertyPath("Opacity"));
    47. sb.Children.Add(doubleAnim);

    48. return sb;
    49. }
    复制代码
    当切换两个地图服务时能够看到一个渐变的效果,这里用到了Silverlight中的动画,它们都是在StoryBoard里面进行的,以后的小节中会讲Silverlight中的动画,这里不再废话了,有兴趣的朋友可以自己参考帮助学习。hidelayername是这个一个公用的string变量,用来在切换的动画效果完成后设置不可见的图层Visible属性。timer也是一个StoryBoard:
    1. <Storyboard x:Name="timer" Completed="timer_Tick" Duration="0:0:5" />
    复制代码
    这里可以看出把StoryBoard也能巧妙的用作计时器。到了特定时间(5秒)后会自动timer_Tick函数,当然也可以使用.net中的各种timer类。
            下面是添加动态服务的部分。
    1. private void chkboxDynamicLayer_Click(object sender, RoutedEventArgs e)
    2. {
    3. if (chkboxDynamicLayer.IsChecked == true)
    4. {
    5. Map1.Layers.Add(california);
    6. Map1.ZoomTo(california.FullExtent);

    7. if (california.IsInitialized == false)
    8. {
    9. chkboxDynamicLayer.IsEnabled = false;
    10. }
    11. chkboxDynamicLayer.Content = "去掉它";
    12. SVlayers.Visibility = Visibility.Visible;
    13. }
    14. else
    15. {
    16. Map1.Layers.Remove(california);
    17. chkboxDynamicLayer.Content = "添加一个动态图层吧";
    18. SVlayers.Visibility = Visibility.Collapsed;
    19. }
    20. }

    21. private void dynamiclayer_initialized(object s, EventArgs e)
    22. {
    23. //若图层没有初始化好就移除图层,当然会报错了,所以这样做就不会了
    24. chkboxDynamicLayer.IsEnabled = true;
    25. Map1.ZoomTo(california.InitialExtent);
    26. SVlayers.Visibility = Visibility.Visible;
    27. california.ID = "layercalifornia";

    28. ESRI.ArcGIS.ArcGISDynamicMapServiceLayer dynamicServiceLayer = s as ESRI.ArcGIS.ArcGISDynamicMapServiceLayer;
    29. if (dynamicServiceLayer.VisibleLayers == null)
    30. dynamicServiceLayer.VisibleLayers = GetDefaultVisibleLayers(dynamicServiceLayer);
    31. UpdateLayerList(dynamicServiceLayer);
    32. }
    复制代码
    当添加了动态服务后,会自动弹出一个listbox,当然这些也都是在xaml中定义好的(加在上面的Canvas后面):
    1. <ScrollViewer x:Name="SVlayers" Width="165" Visibility="Collapsed" Height="120">
    2. <ListBox x:Name="LayerVisibilityListBox" >
    3. <ListBox.ItemTemplate>
    4. <DataTemplate>
    5. <CheckBox Margin="2" Name="{Binding LayerIndex}" Content="{Binding LayerName}"
    6. Tag="{Binding ServiceName}" IsChecked="{Binding Visible}"
    7. ClickMode="Press" Click="chkboxToggleVilible_Click" />
    8. </DataTemplate>
    9. </ListBox.ItemTemplate>
    10. </ListBox>
    11. </ScrollViewer>
    复制代码
    这里把ListBox放到了ScrollVierwer中,固定了它的高度,当内容过多时可以自动显示纵向滚动条。这里要提一下,ListBox的内容用到了数据绑定(参考xaml中的DataBinding,有OneTime,OneWay和TwoWay三种模式,这里使用的是默认的OneWay),看起来里面只有一个CheckBox,但它相当于一个模板,在code-behind中设置了ListBox.ItemSource之后,根据该属性的内容自动生成多个CheckBox。代码中自定义了一个LayerListData类,它的几个属性分别与上面的CheckBox属性绑定;将一个List赋给了ListBox.ItemSource,则会自动生成ListBox中的内容。通过一个List类型变量,来控制动态服务的可见图层。代码如下:
    1. public class LayerListData
    2. {
    3. public bool Visible { get; set; }
    4. public string ServiceName { get; set; }
    5. public string LayerName { get; set; }
    6. public int LayerIndex { get; set; }
    7. }

    8. private int[] GetDefaultVisibleLayers(ESRI.ArcGIS.ArcGISDynamicMapServiceLayer dynamicService)
    9. {
    10. List<int> visibleLayerIDList = new List<int>();

    11. ESRI.ArcGIS.LayerInfo[] layerInfoArray = dynamicService.Layers;

    12. for (int index = 0; index < layerInfoArray.Length; index++)
    13. {
    14. if (layerInfoArray[index].DefaultVisibility)
    15. visibleLayerIDList.Add(index);
    16. }

    17. return visibleLayerIDList.ToArray();
    18. }

    19. private void UpdateLayerList(ESRI.ArcGIS.ArcGISDynamicMapServiceLayer dynamicServiceLayer)
    20. {
    21. int[] visibleLayerIDs = dynamicServiceLayer.VisibleLayers;

    22. if (visibleLayerIDs == null)
    23. visibleLayerIDs = GetDefaultVisibleLayers(dynamicServiceLayer);

    24. List<LayerListData> visibleLayerList = new List<LayerListData>();

    25. ESRI.ArcGIS.LayerInfo[] layerInfoArray = dynamicServiceLayer.Layers;

    26. for (int index = 0; index < layerInfoArray.Length; index++)
    27. {
    28. visibleLayerList.Add(new LayerListData()
    29. {
    30. Visible = visibleLayerIDs.Contains(index),
    31. ServiceName = dynamicServiceLayer.ID,
    32. LayerName = layerInfoArray[index].Name,
    33. LayerIndex = index
    34. });
    35. }

    36. LayerVisibilityListBox.ItemsSource = visibleLayerList;
    37. }

    38. void chkboxToggleVilible_Click(object sender, RoutedEventArgs e)
    39. {
    40. CheckBox tickedCheckBox = sender as CheckBox;

    41. string serviceName = tickedCheckBox.Tag.ToString();
    42. bool visible = (bool)tickedCheckBox.IsChecked;

    43. int layerIndex = Int32.Parse(tickedCheckBox.Name);

    44. ESRI.ArcGIS.ArcGISDynamicMapServiceLayer dynamicServiceLayer = Map1.Layers[serviceName] as
    45. ESRI.ArcGIS.ArcGISDynamicMapServiceLayer;

    46. List<int> visibleLayerList =
    47. dynamicServiceLayer.VisibleLayers != null
    48. ? dynamicServiceLayer.VisibleLayers.ToList() : new List<int>();

    49. if (visible)
    50. {
    51. if (!visibleLayerList.Contains(layerIndex))
    52. visibleLayerList.Add(layerIndex);
    53. }
    54. else
    55. {
    56. if (visibleLayerList.Contains(layerIndex))
    57. visibleLayerList.Remove(layerIndex);
    58. }

    59. dynamicServiceLayer.VisibleLayers = visibleLayerList.ToArray();
    60. }
    复制代码
    5、比例尺。
            Silverlight API提供了一个ScaleBar类,可以方便的设置地图比例尺。
    1. <!--scale bar 放在LayoutRoot Grid中-->
    2. <Canvas HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="10,0,0,20">
    3. <esri:ScaleBar x:Name="scalebar" MapUnit="DecimalDegrees" DisplayUnit="Kilometers" Foreground="Black" FillColor1="White" FillColor2="Blue" />
    4. </Canvas>
    复制代码
    需要在初始化的时候设置scalebar的Map属性,顺便来看看整个页面的初始化工作:
    1. namespace demo_02_extendedmap
    2. {
    3. public partial class Page : UserControl
    4. {
    5. private ESRI.ArcGIS.ArcGISDynamicMapServiceLayer california = new ESRI.ArcGIS.ArcGISDynamicMapServiceLayer();
    6. private string hidelayername;

    7. public Page()
    8. {
    9. InitializeComponent();

    10. scalebar.Map = Map1;
    11. scalebarstoryboard.Begin();
    12. TBzoomdurationvalue.Text = string.Format("当前值:{0}.{1}秒", Map1.ZoomDuration.Seconds, Map1.ZoomDuration.Milliseconds);
    13. TBpandurationvalue.Text = string.Format("当前值:{0}.{1}秒", Map1.PanDuration.Seconds, Map1.PanDuration.Milliseconds);
    14. california.Url = "http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Specialty/ESRI_StatesCitiesRivers_USA/MapServer";
    15. california.Opacity = 0.5;
    16. california.Initialized += new EventHandler<EventArgs>(dynamiclayer_initialized);

    17. TBimagery.IsChecked = true;
    18. makestoryboard("WorldImageLayer", 0, 1).Begin();
    19. //切换全屏/窗口
    20. Application.Current.Host.Content.FullScreenChanged += new EventHandler(fullscreen_changed);
    21. }
    22. }
    23. }
    复制代码
    scalebarstoryboard是xaml里自定义的一个动画,效果见比例尺旁的单位。

    6、地图相关操作。
            Map控件已经内置了一些键盘鼠标事件,但目前不能像JavascriptAPI中那样禁用这些事件。这里还用到了Silverlight程序的一个全屏特性,其实是对Application.Current.Host.Content的一个属性做了设置。直接看代码吧:
    1. <!--operation info-->
    2. <Canvas Width="215" Height="110" Margin="0,0,0,30" VerticalAlignment="Bottom">
    3. <Rectangle Style="{StaticResource rectBottom}" />
    4. <Rectangle Style="{StaticResource rectMiddle}" Fill="#77FF0000" />
    5. <Rectangle Style="{StaticResource rectTop}" />
    6. <TextBlock Margin="20,15,15,0" TextWrapping="Wrap"
    7. Text="地图操作提示:双击放大 Shift+拖拽:放大到指定范围 Ctrl+Shift+拖拽:缩小到指定范围" />
    8. <ToggleButton x:Name="TBfullscreen" Content="点击切换地图全屏" HorizontalAlignment="Center" Canvas.Left="100" Canvas.Top="15" Height="30" Click="TBfullscreen_Click" />
    9. </Canvas>
    复制代码
    放到Gridright Grid中,
    1. private void TBfullscreen_Click(object sender, RoutedEventArgs e)
    2. {
    3. System.Windows.Interop.Content content = Application.Current.Host.Content;
    4. content.IsFullScreen=!content.IsFullScreen;
    5. }

    6. private void fullscreen_changed(object o,EventArgs e)
    7. {
    8. System.Windows.Interop.Content content=Application.Current.Host.Content;
    9. TBfullscreen.IsChecked = content.IsFullScreen;
    10. }
    复制代码
    7、进度条。
            最后还剩下地图中的这个进度条。利用了Map控件内置的一个Progress事件。
    1. <!--progressbar 放在LayoutRoot中-->
    2. <Grid HorizontalAlignment="Center" x:Name="progressGrid" VerticalAlignment="Center" Width="200" Height="20" Margin="5,5,5,5">
    3. <ProgressBar x:Name="MyProgressBar" Minimum="0" Maximum="100" />
    4. <TextBlock x:Name="ProgressValueTextBlock" Text="100%" HorizontalAlignment="Center" VerticalAlignment="Center" />
    5. </Grid>
    复制代码
    在esri:Map标签中加入一个事件:Progress="Map1_Progress",
    1. private void Map1_Progress(object sender, ESRI.ArcGIS.ProgressEventArgs e)
    2. {
    3. if (e.Progress < 100)
    4. {
    5. progressGrid.Visibility = Visibility.Visible;
    6. MyProgressBar.Value = e.Progress;
    7. ProgressValueTextBlock.Text = String.Format("正在处理 {0}%", e.Progress);
    8. }
    9. else
    10. {
    11. progressGrid.Visibility = Visibility.Collapsed;
    12. }
    13. }
    复制代码
    好了到此就已经讲完了整个地图功能。尽管想尽可能详细说明每段代码,便于初学的朋友学习,但也不可能面面俱到。没有讲明白的地方大家可以自己思考,查帮助。学习的过程中,不思考,无进步。
    原文地址:http://bbs.esrichina-bj.cn/ESRI/thread-44365-1-1.html
  • 相关阅读:
    C++ 将对象写入文件 并读取
    IronPython fail to add reference to WebDriver.dll
    How to Capture and Decrypt Lync Server 2010 TLS Traffic Using Microsoft Tools
    .net code injection
    数学系学生应该知道的十个学术网站
    Difference Between Currency Swap and FX Swap
    Swift开源parser
    谈谈我对证券公司一些部门的理解(前、中、后台)[z]
    JDK8记FullGC时候Metaspace内存不会被垃圾回收
    JVM源码分析之JDK8下的僵尸(无法回收)类加载器[z]
  • 原文地址:https://www.cnblogs.com/wenjl520/p/1494141.html
Copyright © 2011-2022 走看看