点击这里,直接看效果。
根据上一节的知识,可以知道这个Silverlight程序里包含了一个Map控件,并且里面至少有一个WorldImagery的图层。那么Page.xaml里的关键代码开起来应该是这样的:
- <Grid x:Name="LayoutRoot">
- <esri:Map x:Name="Map1">
- <esri:Map.Layers>
- <esri:ArcGISTiledMapServiceLayer ID="WorldImageLayer" x:Name="WorldImageLayer" Initialized="WorldImageLayer_Initialized"
- Url="http://services.arcgisonline.com/ArcGIS/rest/services/ESRI_Imagery_World_2D/MapServer" />
- </esri:Map.Layers>
- </esri:Map>
- </Grid>
下面就对这个例子中的每一部分来做说明(与上图中的序号相对应)。
1、当地图移动时获取地图范围。
当地图范围改变后,显示出当前地图范围的边界值。
这部分的页面布局是这样的:
- <Grid x:Name="Gridright" Margin="0,15,20,0" HorizontalAlignment="Right" VerticalAlignment="Stretch">
- <!--extent-->
- <Canvas Width="215" Height="110" VerticalAlignment="Top">
- <Rectangle Style="{StaticResource rectBottom}" />
- <Rectangle Style="{StaticResource rectMiddle}" />
- <Rectangle Style="{StaticResource rectTop}" />
- <TextBlock x:Name="TBextent" Margin="20,15,15,0" Text="范围:" TextWrapping="Wrap" FontWeight="Bold" />
- </Canvas>
- </Grid>
- <Application.Resources>
- <Style x:Key="rectBottom" TargetType="Rectangle">
- <Setter Property="RadiusX" Value="10" />
- <Setter Property="RadiusY" Value="10" />
- <Setter Property="Fill" Value="#22000000" />
- <Setter Property="Canvas.Left" Value="5" />
- <Setter Property="Canvas.Top" Value="5" />
- <Setter Property="Width" Value="215" />
- <Setter Property="Height" Value="110" />
- </Style>
- <Style x:Key="rectMiddle" TargetType="Rectangle">
- <Setter Property="RadiusX" Value="10" />
- <Setter Property="RadiusY" Value="10" />
- <Setter Property="Fill" Value="#775C90B2" />
- <Setter Property="Canvas.Left" Value="0" />
- <Setter Property="Canvas.Top" Value="0" />
- <Setter Property="Width" Value="215" />
- <Setter Property="Height" Value="110" />
- <Setter Property="Stroke" Value="Gray" />
- </Style>
- <Style x:Key="rectTop" TargetType="Rectangle">
- <Setter Property="RadiusX" Value="5" />
- <Setter Property="RadiusY" Value="5" />
- <Setter Property="Fill" Value="#FFFFFFFF" />
- <Setter Property="Canvas.Left" Value="10" />
- <Setter Property="Canvas.Top" Value="10" />
- <Setter Property="Width" Value="195" />
- <Setter Property="Height" Value="90" />
- <Setter Property="Stroke" Value="DarkGreen" />
- </Style>
- </Application.Resources>
- <Rectangle RadiusX="10" RadiusY="10" Fill="#22000000" Canvas.Left="5" Canvas.Top="5" Width="215" Height="110" />
- <Rectangle RadiusX="10" RadiusY="10" Fill="#775C90B2" Canvas.Left="0" Canvas.Top="0" Width="215" Height="110" Stroke="Gray" />
- <Rectangle RadiusX="5" RadiusY="5" Fill="#FFFFFFFF" Canvas.Left="10" Canvas.Top="10" Width="195" Height="90" Stroke="DarkGreen" />
Map控件里面已经封装了一些事件来供我们使用,我们可以在需要的时候捕获它们来进行处理。如果做过ArcGIS产品的二次开发,你应该已经想到我们要捕获的就是Map的ExtentChanged事件;而要在地图移动或者缩放的过程中也实时显示地图范围,则还要对ExtentChanging事件做处理。细心的你可能已经发现,在上面的xaml代码中已经对世界地图这个图层的Initialized事件添加了一个hanlder:WorldImageLayer_Initialized。当然可以像这样一样给Map的这两个事件添加handler,但这里并不这么做,而是在世界地图图层的Initialized事件里来绑定它们(移动地图时出发ExtentChanged事件,网速过慢导致图层并未加入到Map中,则会报错)。来看看Page.xaml.cs中的code-behind代码:
- private void WorldImageLayer_Initialized(object sender, EventArgs e)
- {
- Map1.ExtentChanged += new EventHandler<ESRI.ArcGIS.ExtentEventArgs>(Map1_ExtentChange);
- Map1.ExtentChanging += new EventHandler<ESRI.ArcGIS.ExtentEventArgs>(Map1_ExtentChange);
- }
- private void Map1_ExtentChange(object sender, ESRI.ArcGIS.ExtentEventArgs e)
- {
- TBextent.Text = string.Format("地图范围:\nMinX:{0}\nMinY:{1}\nMaxX:{2}\nMaxY:{3}",
- e.NewExtent.XMin, e.NewExtent.YMin, e.NewExtent.XMax, e.NewExtent.YMax);
- }
对于Silverlight API中内容,是不是感觉很容易呢(当然你得做够xaml的功课才行)?那么赶快来看第二部分。
2、当鼠标移动时获取鼠标坐标。
包括屏幕坐标和地图坐标。外观样式方面是这样的:
- <!--mouse coords-->
- <Canvas Width="215" Height="110" Margin="0,120,0,0" VerticalAlignment="Top">
- <Rectangle Style="{StaticResource rectBottom}" />
- <Rectangle Style="{StaticResource rectMiddle}" />
- <Rectangle Style="{StaticResource rectTop}" />
- <StackPanel Orientation="Vertical" Margin="20,15,15,0">
- <TextBlock x:Name="TBscreencoords"
- HorizontalAlignment="Left" VerticalAlignment="Center" Text="屏幕坐标:" TextWrapping="Wrap" FontWeight="Bold" />
- <TextBlock x:Name="TBmapcoords"
- HorizontalAlignment="Left" VerticalAlignment="Center" Text="地图坐标:" TextWrapping="Wrap" FontWeight="Bold" />
- </StackPanel>
- </Canvas>
- private void Map1_MouseMove(object sender, MouseEventArgs e)
- {
- if (Map1.Extent != null)
- {
- System.Windows.Point screenPnt = e.GetPosition(Map1);
- TBscreencoords.Text = string.Format("屏幕坐标:\nX:{0},Y:{1}", screenPnt.X, screenPnt.Y);
- ESRI.ArcGIS.Geometry.MapPoint mapPnt = Map1.ScreenToMap(screenPnt);
- TBmapcoords.Text = string.Format("地图坐标:\nX:{0}\nY:{1}", Math.Round(mapPnt.X, 4), Math.Round(mapPnt.Y, 4));
- }
- }
3、Map里的动画效果。
当地图放大和平移时都可以看到平滑的效果,这归功于Silverlight的动画功能。Map在封装完动画效果后,给了我们两个属性来对它们进行设置:PanDuration和ZoomDuration,用于设置这两个动作持续的时间。它们都是TimeSpan类型的变量,合理的设置可以带来良好的用户体验。看看这部分的布局:
- <!--map animation slider-->
- <Canvas Width="215" Height="130" Margin="0,240,0,0" VerticalAlignment="Top">
- <Rectangle Style="{StaticResource rectBottom}" Height="130" />
- <Rectangle Style="{StaticResource rectMiddle}" Height="130" />
- <Rectangle Style="{StaticResource rectTop}" Height="110" />
- <StackPanel Orientation="Vertical" Margin="20,15,15,0">
- <TextBlock HorizontalAlignment="Left" Text="设置地图缩放动作持续时间:" TextWrapping="Wrap" FontWeight="Bold" />
- <TextBlock x:Name="TBzoomdurationvalue" HorizontalAlignment="Left" Text="当前值:" TextWrapping="Wrap" FontWeight="Bold" />
- <Slider x:Name="sliderzoomanimation" Orientation="Horizontal" Minimum="0" Maximum="20" SmallChange="1"
- LargeChange="5" Cursor="Hand" ValueChanged="slideranimation_ValueChanged" Width="180" />
- <TextBlock HorizontalAlignment="Left" Text="设置地图平移动作持续时间:" TextWrapping="Wrap" FontWeight="Bold" />
- <TextBlock x:Name="TBpandurationvalue" HorizontalAlignment="Left" Text="当前值:" TextWrapping="Wrap" FontWeight="Bold" />
- <Slider x:Name="sliderpananimation" Orientation="Horizontal" Minimum="0" Maximum="20" SmallChange="1"
- LargeChange="5" Cursor="Hand" ValueChanged="slideranimation_ValueChanged" Width="180" />
- </StackPanel>
- </Canvas>
- private void slideranimation_ValueChanged(object sender, RoutedPropertyChangedEventArgs e)
- {
- Slider s=sender as Slider;
- if (s.Name == "sliderzoomanimation")
- {
- Map1.ZoomDuration = new TimeSpan(0, 0, Convert.ToInt32(sliderzoomanimation.Value));
- TBzoomdurationvalue.Text = string.Format("当前值:{0}秒", Convert.ToInt32(sliderzoomanimation.Value));
- }
- else
- {
- Map1.PanDuration = new TimeSpan(0, 0, Convert.ToInt32(sliderpananimation.Value));
- TBpandurationvalue.Text = string.Format("当前值:{0}秒", Convert.ToInt32(sliderpananimation.Value));
- }
- }
4、对地图服务可见性与动态地图服务中图层可见性的控制。
还是要强调一下,WorldImagery和StreetMap两个能看到的地图实际上都是地图服务,当作layer加入到了Map控件中;而动态地图服务USA中的图层Cities,Rivers,States才是与ArcMap中图层相对的概念。对于WorldImagery和StreetMap之间的切换,主要用到了Silverlight API里Layer的
Visible属性;而动态服务中图层可见性的操作,主要是对ArcGISDynamicMapServiceLayer的VisibleLayers数组做了设置。
StreetMap这个服务其实一开始就加入了地图(在esri:Map标签中):
- <esri:ArcGISTiledMapServiceLayer ID="StreetMapLayer"
- Url="http://services.arcgisonline.com/ArcGIS/rest/services/ESRI_StreetMap_World_2D/MapServer" Visible="False" />
看看布局部分:
- <StackPanel HorizontalAlignment="Left" Margin="20,15,0,0">
- <Canvas x:Name="Canvasleft" Width="165" Height="90" HorizontalAlignment="Left" VerticalAlignment="Top">
- <Rectangle Style="{StaticResource rectBottom}" Width="165" Height="90" />
- <Rectangle Style="{StaticResource rectMiddle}" Fill="#7758FF00" Width="165" Height="90" />
- <Rectangle Style="{StaticResource rectTop}" Width="145" Height="70" />
- <!--change layer-->
- <StackPanel Margin="20,15,15,0">
- <TextBlock Text="切换图层:" TextWrapping="Wrap" FontWeight="Bold" />
- <StackPanel Orientation="Horizontal">
- <ToggleButton x:Name="TBimagery" Content="Imagery" Click="TBimagery_Clicked" Cursor="Hand" />
- <ToggleButton x:Name="TBstreetmap" Content="StreetMap" Click="TBstreetmap_Clicked" Cursor="Hand" />
- </StackPanel>
- <CheckBox Margin="0,5,0,0" x:Name="chkboxDynamicLayer" Content="添加一个动态图层吧" IsChecked="False" Click="chkboxDynamicLayer_Click" Cursor="Hand" />
- </StackPanel>
- </Canvas>
- </StackPanel>
- private void TBimagery_Clicked(object sender, RoutedEventArgs e)
- {
- if (TBstreetmap.IsChecked==true)
- {
- Map1.Layers["WorldImageLayer"].Visible = true;
- Map1.Layers["WorldImageLayer"].Opacity = 0;
- TBstreetmap.IsChecked = false;
- Storyboard sbworldmapshow = makestoryboard("WorldImageLayer", 0, 1);
- Storyboard sbstreetmaphide = makestoryboard("StreetMapLayer", 1, 0);
- sbworldmapshow.Begin();
- sbstreetmaphide.Begin();
- hidelayername = "StreetMapLayer";
- timer.Begin();
- }
- TBimagery.IsChecked = true;
- }
- private void TBstreetmap_Clicked(object sender, RoutedEventArgs e)
- {
- if (TBimagery.IsChecked==true)
- {
- Map1.Layers["StreetMapLayer"].Visible = true;
- Map1.Layers["StreetMapLayer"].Opacity = 0;
- TBimagery.IsChecked = false;
- Storyboard sbstreetmapshow = makestoryboard("StreetMapLayer", 0, 1);
- Storyboard sbworldmaphide = makestoryboard("WorldImageLayer", 1, 0);
- sbstreetmapshow.Begin();
- sbworldmaphide.Begin();
- hidelayername = "WorldImageLayer";
- timer.Begin();
- }
- TBstreetmap.IsChecked = true;
- }
- private void timer_Tick(object sender, EventArgs e)
- {
- Map1.Layers[hidelayername].Visible = false;
- }
- public Storyboard makestoryboard(string layername, double from, double to)
- {
- Storyboard sb = new Storyboard();
- ESRI.ArcGIS.ArcGISTiledMapServiceLayer layer = Map1.Layers[layername] as ESRI.ArcGIS.ArcGISTiledMapServiceLayer;
- DoubleAnimation doubleAnim = new DoubleAnimation();
- doubleAnim.Duration = new TimeSpan(0, 0, 5);
- doubleAnim.From = from;
- doubleAnim.To = to;
- Storyboard.SetTarget(doubleAnim, layer);
- Storyboard.SetTargetProperty(doubleAnim, new PropertyPath("Opacity"));
- sb.Children.Add(doubleAnim);
- return sb;
- }
- <Storyboard x:Name="timer" Completed="timer_Tick" Duration="0:0:5" />
下面是添加动态服务的部分。
- private void chkboxDynamicLayer_Click(object sender, RoutedEventArgs e)
- {
- if (chkboxDynamicLayer.IsChecked == true)
- {
- Map1.Layers.Add(california);
- Map1.ZoomTo(california.FullExtent);
- if (california.IsInitialized == false)
- {
- chkboxDynamicLayer.IsEnabled = false;
- }
- chkboxDynamicLayer.Content = "去掉它";
- SVlayers.Visibility = Visibility.Visible;
- }
- else
- {
- Map1.Layers.Remove(california);
- chkboxDynamicLayer.Content = "添加一个动态图层吧";
- SVlayers.Visibility = Visibility.Collapsed;
- }
- }
- private void dynamiclayer_initialized(object s, EventArgs e)
- {
- //若图层没有初始化好就移除图层,当然会报错了,所以这样做就不会了
- chkboxDynamicLayer.IsEnabled = true;
- Map1.ZoomTo(california.InitialExtent);
- SVlayers.Visibility = Visibility.Visible;
- california.ID = "layercalifornia";
- ESRI.ArcGIS.ArcGISDynamicMapServiceLayer dynamicServiceLayer = s as ESRI.ArcGIS.ArcGISDynamicMapServiceLayer;
- if (dynamicServiceLayer.VisibleLayers == null)
- dynamicServiceLayer.VisibleLayers = GetDefaultVisibleLayers(dynamicServiceLayer);
- UpdateLayerList(dynamicServiceLayer);
- }
- <ScrollViewer x:Name="SVlayers" Width="165" Visibility="Collapsed" Height="120">
- <ListBox x:Name="LayerVisibilityListBox" >
- <ListBox.ItemTemplate>
- <DataTemplate>
- <CheckBox Margin="2" Name="{Binding LayerIndex}" Content="{Binding LayerName}"
- Tag="{Binding ServiceName}" IsChecked="{Binding Visible}"
- ClickMode="Press" Click="chkboxToggleVilible_Click" />
- </DataTemplate>
- </ListBox.ItemTemplate>
- </ListBox>
- </ScrollViewer>
- public class LayerListData
- {
- public bool Visible { get; set; }
- public string ServiceName { get; set; }
- public string LayerName { get; set; }
- public int LayerIndex { get; set; }
- }
- private int[] GetDefaultVisibleLayers(ESRI.ArcGIS.ArcGISDynamicMapServiceLayer dynamicService)
- {
- List<int> visibleLayerIDList = new List<int>();
- ESRI.ArcGIS.LayerInfo[] layerInfoArray = dynamicService.Layers;
- for (int index = 0; index < layerInfoArray.Length; index++)
- {
- if (layerInfoArray[index].DefaultVisibility)
- visibleLayerIDList.Add(index);
- }
- return visibleLayerIDList.ToArray();
- }
- private void UpdateLayerList(ESRI.ArcGIS.ArcGISDynamicMapServiceLayer dynamicServiceLayer)
- {
- int[] visibleLayerIDs = dynamicServiceLayer.VisibleLayers;
- if (visibleLayerIDs == null)
- visibleLayerIDs = GetDefaultVisibleLayers(dynamicServiceLayer);
- List<LayerListData> visibleLayerList = new List<LayerListData>();
- ESRI.ArcGIS.LayerInfo[] layerInfoArray = dynamicServiceLayer.Layers;
- for (int index = 0; index < layerInfoArray.Length; index++)
- {
- visibleLayerList.Add(new LayerListData()
- {
- Visible = visibleLayerIDs.Contains(index),
- ServiceName = dynamicServiceLayer.ID,
- LayerName = layerInfoArray[index].Name,
- LayerIndex = index
- });
- }
- LayerVisibilityListBox.ItemsSource = visibleLayerList;
- }
- void chkboxToggleVilible_Click(object sender, RoutedEventArgs e)
- {
- CheckBox tickedCheckBox = sender as CheckBox;
- string serviceName = tickedCheckBox.Tag.ToString();
- bool visible = (bool)tickedCheckBox.IsChecked;
- int layerIndex = Int32.Parse(tickedCheckBox.Name);
- ESRI.ArcGIS.ArcGISDynamicMapServiceLayer dynamicServiceLayer = Map1.Layers[serviceName] as
- ESRI.ArcGIS.ArcGISDynamicMapServiceLayer;
- List<int> visibleLayerList =
- dynamicServiceLayer.VisibleLayers != null
- ? dynamicServiceLayer.VisibleLayers.ToList() : new List<int>();
- if (visible)
- {
- if (!visibleLayerList.Contains(layerIndex))
- visibleLayerList.Add(layerIndex);
- }
- else
- {
- if (visibleLayerList.Contains(layerIndex))
- visibleLayerList.Remove(layerIndex);
- }
- dynamicServiceLayer.VisibleLayers = visibleLayerList.ToArray();
- }
Silverlight API提供了一个ScaleBar类,可以方便的设置地图比例尺。
- <!--scale bar 放在LayoutRoot Grid中-->
- <Canvas HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="10,0,0,20">
- <esri:ScaleBar x:Name="scalebar" MapUnit="DecimalDegrees" DisplayUnit="Kilometers" Foreground="Black" FillColor1="White" FillColor2="Blue" />
- </Canvas>
- namespace demo_02_extendedmap
- {
- public partial class Page : UserControl
- {
- private ESRI.ArcGIS.ArcGISDynamicMapServiceLayer california = new ESRI.ArcGIS.ArcGISDynamicMapServiceLayer();
- private string hidelayername;
- public Page()
- {
- InitializeComponent();
- scalebar.Map = Map1;
- scalebarstoryboard.Begin();
- TBzoomdurationvalue.Text = string.Format("当前值:{0}.{1}秒", Map1.ZoomDuration.Seconds, Map1.ZoomDuration.Milliseconds);
- TBpandurationvalue.Text = string.Format("当前值:{0}.{1}秒", Map1.PanDuration.Seconds, Map1.PanDuration.Milliseconds);
- california.Url = "http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Specialty/ESRI_StatesCitiesRivers_USA/MapServer";
- california.Opacity = 0.5;
- california.Initialized += new EventHandler<EventArgs>(dynamiclayer_initialized);
- TBimagery.IsChecked = true;
- makestoryboard("WorldImageLayer", 0, 1).Begin();
- //切换全屏/窗口
- Application.Current.Host.Content.FullScreenChanged += new EventHandler(fullscreen_changed);
- }
- }
- }
6、地图相关操作。
Map控件已经内置了一些键盘鼠标事件,但目前不能像JavascriptAPI中那样禁用这些事件。这里还用到了Silverlight程序的一个全屏特性,其实是对Application.Current.Host.Content的一个属性做了设置。直接看代码吧:
- <!--operation info-->
- <Canvas Width="215" Height="110" Margin="0,0,0,30" VerticalAlignment="Bottom">
- <Rectangle Style="{StaticResource rectBottom}" />
- <Rectangle Style="{StaticResource rectMiddle}" Fill="#77FF0000" />
- <Rectangle Style="{StaticResource rectTop}" />
- <TextBlock Margin="20,15,15,0" TextWrapping="Wrap"
- Text="地图操作提示:双击放大 Shift+拖拽:放大到指定范围 Ctrl+Shift+拖拽:缩小到指定范围" />
- <ToggleButton x:Name="TBfullscreen" Content="点击切换地图全屏" HorizontalAlignment="Center" Canvas.Left="100" Canvas.Top="15" Height="30" Click="TBfullscreen_Click" />
- </Canvas>
- private void TBfullscreen_Click(object sender, RoutedEventArgs e)
- {
- System.Windows.Interop.Content content = Application.Current.Host.Content;
- content.IsFullScreen=!content.IsFullScreen;
- }
- private void fullscreen_changed(object o,EventArgs e)
- {
- System.Windows.Interop.Content content=Application.Current.Host.Content;
- TBfullscreen.IsChecked = content.IsFullScreen;
- }
最后还剩下地图中的这个进度条。利用了Map控件内置的一个Progress事件。
- <!--progressbar 放在LayoutRoot中-->
- <Grid HorizontalAlignment="Center" x:Name="progressGrid" VerticalAlignment="Center" Width="200" Height="20" Margin="5,5,5,5">
- <ProgressBar x:Name="MyProgressBar" Minimum="0" Maximum="100" />
- <TextBlock x:Name="ProgressValueTextBlock" Text="100%" HorizontalAlignment="Center" VerticalAlignment="Center" />
- </Grid>
- private void Map1_Progress(object sender, ESRI.ArcGIS.ProgressEventArgs e)
- {
- if (e.Progress < 100)
- {
- progressGrid.Visibility = Visibility.Visible;
- MyProgressBar.Value = e.Progress;
- ProgressValueTextBlock.Text = String.Format("正在处理 {0}%", e.Progress);
- }
- else
- {
- progressGrid.Visibility = Visibility.Collapsed;
- }
- }
好了到此就已经讲完了整个地图功能。尽管想尽可能详细说明每段代码,便于初学的朋友学习,但也不可能面面俱到。没有讲明白的地方大家可以自己思考,查帮助。学习的过程中,不思考,无进步。
原文地址:http://bbs.esrichina-bj.cn/ESRI/thread-44365-1-1.html
本文转自温景良(Jason)博客园博客,原文链接:http://www.cnblogs.com/wenjl520/archive/2009/06/02/1494141.html,如需转载请自行联系原作者