Bing Maps Silverlight Control虽然为我们提供了简洁、方面的开发模型,但也有许多不足之处,比如我们想实现一个迷你小地图功能,Bing Map Silverlight Control就没有这样的内置控件,要想实现这一功能就需要我们自己想办法。当然您也可以使用第三方提供的相关扩展组件去实现这一功能,比如我在上一篇文章中所介绍到的DeepEarth所提供的MiniMap控件,详细请查阅《
Bing Maps进阶系列五:通过DeepEarth的MiniMap控件为Bing Maps扩展迷你小地图》。
介绍如何实现迷你小地图前先得先了解下Silverlight中对象的剪切(Clip)特性,Silverlight中提供五种对象剪切特性,它们分别是GeometryGroup、LineGeometry、PathGeometry、EllipseGeometry和RectangleGeometry,通过这五种对象剪切特性基本上可以用来完成我们在开发中常用的剪切操作。具体的使用方式这里不作介绍,详细可查询MSDN(
http://msdn.microsoft.com/zh-cn/library/system.windows.uielement.clip(VS.95).aspx)或其他相关资料。
在了解过Silverlight的对象剪切(Clip)特性后在来实现迷你小地图的功能就非常简单了,实际上界面上就是布局的两个地图,而迷你小地图则通过Silverlight剪切技术剪切出我们想实现的图形效果就OK了。然后就将外围的大地图和小地图的位置同步,让其在放大或缩小的同时大小地图的显示是同步的。如下是xaml的代码块:
<Grid x:Name="LayoutRoot">
<m:Map x:Name="map" Margin="0,0,0,0" CredentialsProvider="{StaticResource MyCredentials}"
MouseClick="map_MouseClick"
ScaleVisibility ="Visible"
CopyrightVisibility ="Collapsed">
<m:MapTileLayer Name="ChinaTileLayer"></m:MapTileLayer>
</m:Map>
<Canvas x:Name="cMiniMap"
Width="200"
Height="200"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Margin="0,5,5,0" >
<m:Map x:Name="MiniMap"
CredentialsProvider="{StaticResource MyCredentials}"
Width ="200"
Height="200"
Mode="Road"
NavigationVisibility="Collapsed"
ScaleVisibility="Collapsed"
LogoVisibility="Collapsed"
CopyrightVisibility ="Collapsed">
<m:Map.Clip> <!--进行圆形几何图形剪切-->
<EllipseGeometry RadiusX="94" RadiusY="94" Center="100,100" />
</m:Map.Clip>
<m:MapTileLayer x:Name="MiniChinaTileLayer"></m:MapTileLayer>
</m:Map>
<Ellipse Width="200" Height="200" Stroke="#FFFCB134" StrokeThickness="6" Margin="0,0,0,0" />
<Ellipse Height="10" Width="10" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="94,94,0,0" x:Name="ellipse" Fill="#FFFCB134" />
</Canvas>
</Grid>
<m:Map x:Name="map" Margin="0,0,0,0" CredentialsProvider="{StaticResource MyCredentials}"
MouseClick="map_MouseClick"
ScaleVisibility ="Visible"
CopyrightVisibility ="Collapsed">
<m:MapTileLayer Name="ChinaTileLayer"></m:MapTileLayer>
</m:Map>
<Canvas x:Name="cMiniMap"
Width="200"
Height="200"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Margin="0,5,5,0" >
<m:Map x:Name="MiniMap"
CredentialsProvider="{StaticResource MyCredentials}"
Width ="200"
Height="200"
Mode="Road"
NavigationVisibility="Collapsed"
ScaleVisibility="Collapsed"
LogoVisibility="Collapsed"
CopyrightVisibility ="Collapsed">
<m:Map.Clip> <!--进行圆形几何图形剪切-->
<EllipseGeometry RadiusX="94" RadiusY="94" Center="100,100" />
</m:Map.Clip>
<m:MapTileLayer x:Name="MiniChinaTileLayer"></m:MapTileLayer>
</m:Map>
<Ellipse Width="200" Height="200" Stroke="#FFFCB134" StrokeThickness="6" Margin="0,0,0,0" />
<Ellipse Height="10" Width="10" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="94,94,0,0" x:Name="ellipse" Fill="#FFFCB134" />
</Canvas>
</Grid>
上面代码块的两个地图(Map)控件都附加了一个MapTileLayer,这是用来通过自定义TileSource加载中文地图所用的,下面是具体的实现代码:
![](http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
public
MainPage()
{
InitializeComponent();
this.Loaded += (o, e) =>
{
//街道图
UriBuilder tileSourceUri = new UriBuilder("http://r2.tiles.ditu.live.com/tiles/r{quadkey}.png?g=49" );
LocationRectTileSource tileSource = new LocationRectTileSource(tileSourceUri.Uri.ToString(),
new LocationRect(new Location(60, 60), new Location(13, 140 )),
new Range<double>(1, 16 ));
ChinaTileLayer.TileSources.Add(tileSource);
ChinaTileLayer.Opacity = 0.9 ;
MiniChinaTileLayer.TileSources.Add(tileSource);
ChinaTileLayer.Opacity = 0.9 ;
map.Mode = new MercatorMode();
map.Center = new Microsoft.Maps.MapControl.Location(29.5076372217973, 106.489384971208 );
map.ZoomLevel = 8 ;
MiniMap.Mode = new MercatorMode();
MiniMap.Center = new Microsoft.Maps.MapControl.Location(29.5076372217973, 106.489384971208 );
MiniMap.ZoomLevel = 8 ;
};
}
{
InitializeComponent();
this.Loaded += (o, e) =>
{
//街道图
UriBuilder tileSourceUri = new UriBuilder("http://r2.tiles.ditu.live.com/tiles/r{quadkey}.png?g=49" );
LocationRectTileSource tileSource = new LocationRectTileSource(tileSourceUri.Uri.ToString(),
new LocationRect(new Location(60, 60), new Location(13, 140 )),
new Range<double>(1, 16 ));
ChinaTileLayer.TileSources.Add(tileSource);
ChinaTileLayer.Opacity = 0.9 ;
MiniChinaTileLayer.TileSources.Add(tileSource);
ChinaTileLayer.Opacity = 0.9 ;
map.Mode = new MercatorMode();
map.Center = new Microsoft.Maps.MapControl.Location(29.5076372217973, 106.489384971208 );
map.ZoomLevel = 8 ;
MiniMap.Mode = new MercatorMode();
MiniMap.Center = new Microsoft.Maps.MapControl.Location(29.5076372217973, 106.489384971208 );
MiniMap.ZoomLevel = 8 ;
};
}
如上就实现了将大小地图都绑定上了直定义的加载中文TileSource,接下来需要做的就是实现大小地图的同步显示,原理就是当大地图的试图改变的时候同时设置小地图的中心地理位置,可以通过地图的TargetViewChanged事件来完成这一功能,在TargetViewChanged事件的处理函数里使用地图的TargetCenter属性来获取到当前地图的中心坐标点,然后将此坐标点设置为小地图的中心坐标点就实现了地图的同步显示。
/// <summary>
/// 当地图试图改变后同步迷你小地图的定位
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void map_TargetViewChanged(object sender, MapEventArgs e)
{
Map m = sender as Map;
this.MiniMap.Center=new Location(m.TargetCenter.Latitude,m.TargetCenter.Longitude);
this.MiniMap.ZoomLevel = map.ZoomLevel;
}
/// 当地图试图改变后同步迷你小地图的定位
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void map_TargetViewChanged(object sender, MapEventArgs e)
{
Map m = sender as Map;
this.MiniMap.Center=new Location(m.TargetCenter.Latitude,m.TargetCenter.Longitude);
this.MiniMap.ZoomLevel = map.ZoomLevel;
}
这样就实现了迷你小地图功能,除此之外我们还可以做一些扩展功能的开发。比如在功能导航条上加上控制迷你小地图的功能按钮,可以设置迷你小地图是否呈现。关于自定义或扩展功能导航菜单的详细实现请查阅《
【Silverlight】Bing Maps学习系列(九):自定义功能导航条(Custom NavigationBar)》 这篇文章里的详细介绍。最终的效果如下图所示:
![](http://images.cnblogs.com/cnblogs_com/beniao/BingMaps/CMiniMap.jpg?x-oss-process=image/resize,w_1400/format,webp)
因为要通过功能导航条实现动态的控制迷你小地图的显示,这里就需要定义一个导航条的Command来实现控制的逻辑处理,如下代码定义:
public class
MiniMapCommand:NavigationBarCommandBase
{
public MiniMapCommand()
{ }
public override void Execute(MapBase map)
{
switch (this .GetStatus(map))
{
case NavigationBarCommandStatus.Checked:
MainPage.MiniCanvas.Visibility = Visibility.Collapsed;
break ;
case NavigationBarCommandStatus.Normal:
MainPage.MiniCanvas.Visibility = Visibility.Visible;
break ;
}
}
public override NavigationBarCommandStatus GetStatus(MapBase map)
{
NavigationBarCommandStatus normal = NavigationBarCommandStatus.Normal;
if (MainPage.MiniCanvas.Visibility == Visibility.Visible)
{
normal = NavigationBarCommandStatus.Checked;
}
return normal;
}
}
{
public MiniMapCommand()
{ }
public override void Execute(MapBase map)
{
switch (this .GetStatus(map))
{
case NavigationBarCommandStatus.Checked:
MainPage.MiniCanvas.Visibility = Visibility.Collapsed;
break ;
case NavigationBarCommandStatus.Normal:
MainPage.MiniCanvas.Visibility = Visibility.Visible;
break ;
}
}
public override NavigationBarCommandStatus GetStatus(MapBase map)
{
NavigationBarCommandStatus normal = NavigationBarCommandStatus.Normal;
if (MainPage.MiniCanvas.Visibility == Visibility.Visible)
{
normal = NavigationBarCommandStatus.Checked;
}
return normal;
}
}
自定义处理迷你小地图的Command完成后,接下来就可以在功能菜单导航条上加上一个功能处理按钮,使用直定义的Command去处理该按钮的行为控制,如下代码块:
this.map.MapForeground.TemplateApplied += (oo, ee) =>
{
this.map.MapForeground.NavigationBar.TemplateApplied += (ooo, eee) =>
{
var navigationBar = this .map.MapForeground.NavigationBar;
navigationBar.HorizontalPanel.Children.Add(new CommandSeparator());
CommandToggleButton btnMini = new CommandToggleButton(new MiniMapCommand(), "迷你地图", "迷你地图" );
navigationBar.HorizontalPanel.Children.Add(btnMini);
};
};
{
this.map.MapForeground.NavigationBar.TemplateApplied += (ooo, eee) =>
{
var navigationBar = this .map.MapForeground.NavigationBar;
navigationBar.HorizontalPanel.Children.Add(new CommandSeparator());
CommandToggleButton btnMini = new CommandToggleButton(new MiniMapCommand(), "迷你地图", "迷你地图" );
navigationBar.HorizontalPanel.Children.Add(btnMini);
};
};
本文转自 beniao 51CTO博客,原文链接:http://blog.51cto.com/beniao/287824,如需转载请自行联系原作者