其实ADF开发中也有GraphicsLayer的概念,同样在其他两个客户端API(JavaScript/Flex)中也能找到GraphicsLayer的身影,它们都是一样一样的。
本节我们主要看如何在GraphicsLayer中展现内容。当然第一个工作就是添加ESRI.ArcGIS.dll的引用,引入esri的xml命名空间;接下来在Map中添加一个GraphicsLayer图层:
<esri:Map x:Name="Map1">
            <esri:Map.Layers>
                <!-- 其他图层 -->
                <esri:GraphicsLayer ID="GLayer" />
            </esri:Map.Layers>
        </esri:Map>要使GraphicsLayer中的内容处于最顶端(不被其他图层内容覆盖),就要将它放在Map标签里的最下头,像上面那样。从命名我们不难看出,GraphicLayer里面放的就是Graphic的集合了。Graphic(ESRI.ArcGIS.Graphic)是GraphicsLayer中的基本元素,它包括了Geometry(在ESRI.ArcGIS.Geometry命名空间中),Symbol(在ESRI.ArcGIS.Symbol命名空间中),Attributes等属性。所有显示在地图中的矢量元素都有一个Geometry,里面包含了若干地理坐标,用于显示地图上地物的形状,它是Point,Polyline,Polygon等的总称,在这里代表了Graphic的形状。Symbol代表了Graphic的外观,它是一系列符号的总称,我们通常跟SimpleMarkerSymbol,SimpleLineSymbol和SimpleFillSymbol等打交道,它们分别对应了上面3种不同的Geometry(Point,Polyline,Polygon)。
要让一个Graphic显示出来,总共分3步:
1、定义Graphic:
在xaml中
<esri:Graphic>
</esri:Graphic>在code-behind中
Graphic g= new Graphic()2、设置Graphic的Geometry和Symbol属性:
在xaml中
<esri:Graphic>
    <esri:Graphic.Symbol>
        <esriSymbols:SimpleMarkerSymbol Color="Blue" Size="12" Style="Square" />
    </esri:Graphic.Symbol>
    <esriGeometry:MapPoint X="108" Y="30" />
</esri:Graphic>在code-behind中
Graphic g = new Graphic()
            {
                Geometry = new MapPoint(108, 30),
                Symbol = new SimpleMarkerSymbol()
                {
                    Color = new SolidColorBrush(Colors.Blue),
                    Size = 12,
                    Style = SimpleMarkerSymbol.SimpleMarkerStyle.Square
                }
            };3、把定义好的Graphic添加到GraphicsLayer里:
在xaml中
<esri:GraphicsLayer ID="GLayer">
    <esri:GraphicsLayer.Graphics>
        <esri:Graphic>
            <esri:Graphic.Symbol>
                <esriSymbols:SimpleMarkerSymbol Color="Blue" Size="12" Style="Square" />
            </esri:Graphic.Symbol>
            <esriGeometry:MapPoint X="108" Y="30" />
        </esri:Graphic>
    </esri:GraphicsLayer.Graphics>
</esri:GraphicsLayer>在code-behind中
Graphic g = new Graphic()
            {
                Geometry = new MapPoint(108, 30),
                Symbol = new SimpleMarkerSymbol()
                {
                    Color = new SolidColorBrush(Colors.Blue),
                    Size = 12,
                    Style = SimpleMarkerSymbol.SimpleMarkerStyle.Square
                }
            };
GraphicsLayer glayer = Map1.Layers["GLayer"] as GraphicsLayer;
glayer.Graphics.Add(g);看一下效果:

图中还有其他的图形,无非是改变了Graphic的Geometry和Symbol属性。图上的那只灰熊是一段动画文件,利用Silverlight的特性,能够定义出表现力丰富的各种符号。
尽管能够完全在xaml中来完成工作,但还是建议将可视化元素的定义放在xaml中,将实现的逻辑部分放在code-behind中。看一下添加图中那些Graphic的代码:
<Grid.Resources>
    <esriSymbols:SimpleMarkerSymbol x:Name="RedMarkerSymbol" Color="Red" Size="12" Style="Circle" />
    <!-- 可惜目前Silverlight只支持Jpeg和PNG格式的图像,所以PictureMarkerSymbol无法显示GIF格式的图像,否则会报ImagingError的错误 -->
    <esriSymbols:PictureMarkerSymbol x:Name="PinPictureMarkerSymbol" Source="imgs/pin.png" OffsetX="10" OffsetY="10" />
    <esriSymbols:SimpleLineSymbol x:Name="RedLineSymbol" Color="Red" Width="4" Style="Solid" />
    <esriSymbols:CartographicLineSymbol x:Name="CartoLineSymbol" Color="Red" Width="10" DashCap="Triangle" LineJoin="Round" DashArray="6,2" />
    <esriSymbols:SimpleFillSymbol x:Name="RedFillSymbol" Fill="#66FF0000" BorderBrush="Red" BorderThickness="2" />
</Grid.Resources>
<MediaElement x:Name="BearVideo" />private void AddGraphics()
        {
            GraphicsLayer glayer = Map1.Layers["GLayer"] as GraphicsLayer;
            Graphic[] graphics = new Graphic[8];
            graphics[0] = new Graphic()
            {
                Geometry = new MapPoint(108, 34),
                Symbol = RedMarkerSymbol
            };
            graphics[1] = new Graphic()
            {
                Geometry = new MapPoint(108, 30),
                Symbol = new SimpleMarkerSymbol()
                {
                    Color = new SolidColorBrush(Colors.Blue),
                    Size = 12,
                    Style = SimpleMarkerSymbol.SimpleMarkerStyle.Square
                }
            };
            graphics[2] = new Graphic()
            {
                Geometry = new MapPoint(108, 25),
                Symbol = PinPictureMarkerSymbol
            };
            graphics[3] = new Graphic()
            {
                Geometry = new MapPoint(108, 20),
                Symbol = new TextSymbol()
                {
                    FontFamily = new FontFamily("微软雅黑, 宋体"),
                    FontSize = 14,
                    Foreground = new SolidColorBrush(Colors.Black),
                    Text = "这是text symbol"
                }
            };
            graphics[4] = new Graphic();
            graphics[4].Symbol = RedLineSymbol;
            ESRI.ArcGIS.Geometry.PointCollection pc = new ESRI.ArcGIS.Geometry.PointCollection()
            {
                new MapPoint(95,10),
                new MapPoint(110,-15),
                new MapPoint(130,10)
            };
            ESRI.ArcGIS.Geometry.Polyline pl = new ESRI.ArcGIS.Geometry.Polyline();
            pl.Paths.Add(pc);
            graphics[4].Geometry = pl;
            graphics[5] = new Graphic();
            graphics[5].Symbol = CartoLineSymbol;
            ESRI.ArcGIS.Geometry.PointCollection pc1 = new ESRI.ArcGIS.Geometry.PointCollection()
            {
                new MapPoint(95,0),
                new MapPoint(110,-25),
                new MapPoint(130,0)
            };
            ESRI.ArcGIS.Geometry.Polyline pl1 = new ESRI.ArcGIS.Geometry.Polyline();
            pl1.Paths.Add(pc1);
            graphics[5].Geometry = pl1;
            graphics[6] = new Graphic()
            {
                Symbol = RedFillSymbol
            };
            ESRI.ArcGIS.Geometry.PointCollection pc2 = new ESRI.ArcGIS.Geometry.PointCollection()
            {
                new MapPoint(110,-30),
                new MapPoint(130,-30),
                new MapPoint(130,-45),
                new MapPoint(120,-55),
                new MapPoint(110,-45),
                new MapPoint(110,-30)
            };
            ESRI.ArcGIS.Geometry.Polygon pg = new ESRI.ArcGIS.Geometry.Polygon();
            pg.Rings.Add(pc2);
            graphics[6].Geometry=pg;
            graphics[7] = new Graphic();
            //MediaElement的Name属性只能在xaml中定义(见帮助),所以决定了MediaElement不能完全在cs代码中定义
            BearVideo.Source = new Uri("http://serverapps.esri.com/media/bear.wmv", UriKind.RelativeOrAbsolute);
            BearVideo.IsHitTestVisible=false;
            BearVideo.IsMuted=true;
            BearVideo.AutoPlay=true;
            BearVideo.Opacity=0;
            ESRI.ArcGIS.Geometry.Polygon pg2 = new ESRI.ArcGIS.Geometry.Polygon();
            ESRI.ArcGIS.Geometry.PointCollection pc3 = new ESRI.ArcGIS.Geometry.PointCollection()
            {
                new MapPoint(10,-20),
                new MapPoint(32,7),
                new MapPoint(62,-35),
                new MapPoint(11,-36),
                new MapPoint(10,-20)
            };
            pg2.Rings.Add(pc3);
            graphics[7].Geometry=pg2;
            graphics[7].Symbol = new SimpleFillSymbol()
            {
                Fill = new VideoBrush()
                {
                    SourceName = BearVideo.Name,
                    Opacity = 0.6,
                    Stretch = Stretch.UniformToFill
                }
            };
            foreach (Graphic g in graphics)
            {
                glayer.Graphics.Add(g);
                g.MouseLeftButtonDown+=new MouseButtonEventHandler(graphic_MouseLeftButtonDown);
            }
        }
        private void graphic_MouseLeftButtonDown(object o,MouseButtonEventArgs e)
        {
            Graphic g=o as Graphic;
            MessageBox.Show(string.Format("Geometry:{0}\nSymbol:{1}",g.Geometry.GetType().ToString(),g.Symbol.GetType().ToString()));
        }可以看到,完全能够在一个Graphic上定义一些事件,来达到程序的目的。大家可以试着把上面的内容在xaml中改写一遍。看到这里肯定会产生一个疑问:难道每个Geometry的定义都这么困难吗?其实Silverlight API已经给我们提供了ESRI.ArcGIS.Draw(继承自xaml中的Canvas)类,它能非常方便的捕捉到用户的鼠标操作,从而获取各种Geometry来供程序使用。
可以把Draw理解成一块画板,调用Draw的Active()方法,就可以开始在画板上面绘画,程序会自动记录鼠标画出的每个Geometry,调用DeActive()方法,停止绘画。Active()有一个DrawMode参数,它决定了我们即将在这个画板上画出的内容类型:Point,Polyline,Polygon等。在画的过程中我们可以看到地图上可以实时反映出我们绘画的内容,而这些则利用了Draw的预定义Symbol:DefaultMarkerSymbol,DefaultLineSymbol,DefaultPolygonSymbol等。对应关系如下:

每当完成一个图形的绘制,就会触发Draw.OnDrawComplete事件,利用事件参数就可以获得Geometry,之后可以创建一个Graphic,设置一个Symbol(一般使用Draw的预定义Symbol),把画好的这个Graphic添加到一个GraphicsLayer中。
点击这里,查看一个比较完整的Graphics的例子。
最后来看一下这个例子的部分代码:
<Grid.Resources>            
            <esriSymbols:SimpleMarkerSymbol x:Name="DefaultMarkerSymbol" Color="Red" Size="12" Style="Circle" />
            <esriSymbols:CartographicLineSymbol x:Name="DefaultLineSymbol" Color="Red" Width="4" />
            <esriSymbols:SimpleFillSymbol x:Name="DefaultFillSymbol" Fill="#33FF0000" BorderBrush="Red" BorderThickness="2" />
            <esriSymbols:SimpleFillSymbol x:Name="DefaultPolygonSymbol" Fill="#33FF0000" BorderBrush="Red" BorderThickness="2" />
        </Grid.Resources>
        
        <esri:Draw x:Name="Draw1" 
                    DefaultRectangleSymbol="{StaticResource DefaultFillSymbol}" 
                    DefaultMarkerSymbol="{StaticResource DefaultMarkerSymbol}"
                    DefaultLineSymbol="{StaticResource DefaultLineSymbol}"
                    DefaultPolygonSymbol="{StaticResource DefaultPolygonSymbol}"
                    Loaded="Draw1_Loaded"
                    OnDrawComplete="Draw1_OnDrawComplete" />
        
        <Canvas VerticalAlignment="Top" HorizontalAlignment="Left" Margin="20,20,0,0" Width="430" Height="110">
            <Rectangle RadiusX="10" RadiusY="10" Width="430" Height="110" Fill="#98000000" Stroke="#FF6495ED" />
            <Rectangle Fill="#FFFFFFFF" Stroke="DarkGray" RadiusX="5" RadiusY="5" Canvas.Left="10" Canvas.Top="10" Width="410" Height="90"  />
            <StackPanel Orientation="Vertical" Canvas.Top="5" Canvas.Left="20">
                <esriWidgets:Toolbar x:Name="ToolBar1" MaxItemHeight="80" MaxItemWidth="80" Width="380" Height="80"
                                     ToolbarIndexChanged="ToolBar1_ToolbarIndexChanged"
                                     ToolbarItemClicked="ToolBar1_ToolbarItemClicked">
                    <esriWidgets:Toolbar.Items>
                        <esriWidgets:ToolbarItemCollection>
                            <esriWidgets:ToolbarItem Text="添加点">
                                <esriWidgets:ToolbarItem.Content>
                                    <Image Source="imgs/DrawPoint.png" Stretch="UniformToFill" Margin="5" />
                                </esriWidgets:ToolbarItem.Content>
                            </esriWidgets:ToolbarItem>
                            <esriWidgets:ToolbarItem Text="添加折线">
                                <esriWidgets:ToolbarItem.Content>
                                    <Image Source="imgs/DrawPolyline.png" Stretch="UniformToFill" Margin="5" />
                                </esriWidgets:ToolbarItem.Content>
                            </esriWidgets:ToolbarItem>
                            <esriWidgets:ToolbarItem Text="添加多边形">
                                <esriWidgets:ToolbarItem.Content>
                                    <Image Source="imgs/DrawPolygon.png" Stretch="UniformToFill" Margin="5" />
                                </esriWidgets:ToolbarItem.Content>
                            </esriWidgets:ToolbarItem>
                            <esriWidgets:ToolbarItem Text="添加矩形">
                                <esriWidgets:ToolbarItem.Content>
                                    <Image Source="imgs/DrawRectangle.png" Stretch="UniformToFill" Margin="5" />
                                </esriWidgets:ToolbarItem.Content>
                            </esriWidgets:ToolbarItem>
                            <esriWidgets:ToolbarItem Text="添加曲线">
                                <esriWidgets:ToolbarItem.Content>
                                    <Image Source="imgs/DrawFreehand.png" Stretch="UniformToFill" Margin="5" />
                                </esriWidgets:ToolbarItem.Content>
                            </esriWidgets:ToolbarItem>
                            <esriWidgets:ToolbarItem Text="停止添加动作">
                                <esriWidgets:ToolbarItem.Content>
                                    <Image Source="imgs/StopDraw.png" Stretch="UniformToFill" Margin="5" />
                                </esriWidgets:ToolbarItem.Content>
                            </esriWidgets:ToolbarItem>
                            <esriWidgets:ToolbarItem Text="清空绘制的图形">
                                <esriWidgets:ToolbarItem.Content>
                                    <Image Source="imgs/eraser.png" Stretch="UniformToFill" Margin="5" />
                                </esriWidgets:ToolbarItem.Content>
                            </esriWidgets:ToolbarItem>
                        </esriWidgets:ToolbarItemCollection>
                    </esriWidgets:Toolbar.Items>
                </esriWidgets:Toolbar>
                <TextBlock x:Name="StatusTextBlock" Text="" FontWeight="Bold" HorizontalAlignment="Center"/>
            </StackPanel>
        </Canvas>private void Draw1_Loaded(object sender, RoutedEventArgs e)
        {
            Draw1.Map = Map1;
        }
        private void Draw1_OnDrawComplete(object sender, ESRI.ArcGIS.DrawEventArgs args)
        {
            ESRI.ArcGIS.GraphicsLayer graphicsLayer = Map1.Layers["GLayer2"] as ESRI.ArcGIS.GraphicsLayer;
            ESRI.ArcGIS.Graphic graphic = new ESRI.ArcGIS.Graphic()
            {
                Geometry = args.Geometry,
                Symbol = _activeSymbol,
            };
            graphicsLayer.Graphics.Add(graphic);
        }
        private void ToolBar1_ToolbarIndexChanged(object sender, ESRI.ArcGIS.Widgets.SelectedToolbarItemArgs e)
        {
            StatusTextBlock.Text = e.Item.Text;
        }
        private void ToolBar1_ToolbarItemClicked(object sender, ESRI.ArcGIS.Widgets.SelectedToolbarItemArgs e)
        {
            Draw1.Deactivate();
            switch (e.Index)
            {
                case 0: // Point
                    Draw1.Activate(ESRI.ArcGIS.DrawMode.Point);
                    _activeSymbol = strobeSymbol;
                    break;
                case 1: // Polyline
                    Draw1.Activate(ESRI.ArcGIS.DrawMode.Polyline);
                    _activeSymbol = DefaultLineSymbol;
                    break;
                case 2: // Polygon
                    Draw1.Activate(ESRI.ArcGIS.DrawMode.Polygon);
                    _activeSymbol = DefaultPolygonSymbol;
                    break;
                case 3: // Rectangle
                    Draw1.Activate(ESRI.ArcGIS.DrawMode.Rectangle);
                    _activeSymbol = DefaultFillSymbol;
                    break;
                case 4: // Freehand
                    Draw1.Activate(ESRI.ArcGIS.DrawMode.Freehand);
                    _activeSymbol = waveLineSymbol;
                    break;
                case 5: // Stop Graphics
                    break;
                case 6: // Clear Graphics
                    ESRI.ArcGIS.GraphicsLayer graphicsLayer = Map1.Layers["GLayer2"] as ESRI.ArcGIS.GraphicsLayer;
                    graphicsLayer.ClearGraphics();
                    break;
            }
        }大家可以注意一下例子中添加的点符号和曲线符号。只要有足够的想象力,完全可以利用Silverlight定制出非常炫的符号效果来。
好了,下一节我们来了解如何使用这些画出的图形与地图数据交互。
 
 

 
 博文
博文
 
 
关注老王的这套博文很久了,写得非常精彩!在目前新API资料欠缺的时候做了这么一项伟大的工作,感谢你!
回复删除好汗颜。。。。。
回复删除我只能仰着脖子看你,脖子都快仰断了,才看到你的影子。
你不晓得我是谁把?
回复删除@①ne:
回复删除呵呵,我也是在学习,和大家共勉:)
@匿名:
不要花那么多时间看头顶的镜子,其实我就在你旁边呢
您好~想請問一個問題
回复删除我做了一個列表如下
ListBox x:Name="MapList" ItemsSource="{Binding ElementName=MyMap, Path=Layers}"
這樣可以反映我所有的Map Service
但當我啟用Draw
都會跑出一層GraphicsLayer
有辦法可以消掉這個嗎?
這困擾我很久了~感激不盡
@佑昌:
回复删除你好,不知道你说的“启用Draw”这个动作是用什么代码完成的?如果是自己在code-behind里添加一个新建一个draw并和map绑定的话,应该不会自动添加graphicslayer的。
之后,关于这个问题:
1、使用API的Draw,就是为了在屏幕上画出图形,而要显示画出的图形,map中必须存在一个graphicslayer才可以;
2、请注意帮助中关于itemssource的一句解释:If ItemsSource is not nullNothingnullptrunita null reference (Nothing in Visual Basic), the items in the items property are read-only. You cannot add an object or change the objects in the Items property。也就是说一旦决定对listbox使用绑定,itemssource不为空,那么就无法在运行时从items里移除任何东西;
3、上面两点就决定了,如果map里有grpahicslayer,而你又使用了绑定的话,那么对于listbox里的graphicslayer一项,就无能为力了。
建议:不使用绑定,利用map.layers的collectionchaged事件,自己手动控制listbox中的内容。
版主如此快速的回覆讓我十分感動~
回复删除反倒是我最近一忙沒有上來看~
拖到現在才回覆,
無論輩分跟禮數上...著實汗顏
我有參考你的建議重做了~
很高興問題解決了 謝謝
@佑昌:
回复删除不用客气,共同学习:)