实现鹰眼图的功能需要两个AxMapControl控件,我们就让axMapControl1作为主视图,axMapControl2作为鹰眼图,在窗体中的摆放位置可以自定义,我是用SplitContainer将Form分割开来:
实现鹰眼图前需要明白鹰眼图的功能:
- 鹰眼图是主视图的缩略图,鹰眼图是主视图的全局视图
- 主视图的当前视图对应鹰眼图中的红框范围
- 鼠标可以点击鹰眼图,主视图对应转换成以点击位置为中心的视图,也可以在鹰眼图上拖出显示范围
整个过程的消息传递机制:
axMapControl1加载主图时,触发其OnMapReplaced
事件,将加载的图层同样加载到鹰眼控件axMapControl2中,当主图的extent变化例如放大缩小事件,会触发主图的OnExtentUpdated
事件,此时设置矩形边框的颜色等参数。另外需要在点击鹰眼图层时(OnMouseDown
事件)使得主图范围随之变化。
1.OnMapReplaced实现
通过这个事件实现主视图axMapControl1和鹰眼图axMapControl2之间的数据共享
官方文档对OnMapReplaced
的描述:
The OnMapReplaced event is triggered whenever the IMapControl2::Map
is replaced by another map, such as when the IMapControl2::LoadMxFile
method is used or when the map property is explicitly replaced. Use this event to keep in synch with the current map.
在这里我是通过下面的语句来加载mxd文档而触发OnMapReplaced
事件
axMapControl1.LoadMxFile(string MxdPath);
在这之前我只是通过给axMapControl1以AddShapeFile
的形式添加图层,发现这样无法触发该事件,具体的原因还得学习
/// <summary>
/// 实现主视图axMapControl1和鹰眼图axMapControl2之间的数据共享
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void axMapControl1_OnMapReplaced(object sender, IMapControlEvents2_OnMapReplacedEvent e)
{
if (axMapControl1.LayerCount > 0)
{
for (int i = 0; i < axMapControl1.LayerCount; i++)
axMapControl2.AddLayer(axMapControl1.get_Layer(i));
axMapControl2.Extent = axMapControl1.FullExtent; // 初始化时设置鹰眼视图为全局视图
axMapControl2.Refresh(); // Extent变化后记得要Refresh
}
}
2.OnMouseDown实现
因为要实现鼠标在鹰眼图中点击的位置是主视图的中心,所以这里获取的是e.mapX和e.mapY
而不是普通的e.X和e.Y
,它们的区别在于前者获取的是地理坐标,后者获取的是屏幕坐标,前者可以在两个视图中对应,而后者不可以
/// <summary>
/// 鼠标在鹰眼图上的点击事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void axMapControl2_OnMouseDown(object sender, IMapControlEvents2_OnMouseDownEvent e)
{
if(axMapControl1.LayerCount > 0)
{
if(e.button == 1) // 左键所点击的位置设置为主视图的中心
{
IPoint pPoint = new PointClass();
pPoint.PutCoords(e.mapX, e.mapY);
axMapControl1.CenterAt(pPoint);
axMapControl1.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGraphics, null, null); //对所有数据所有范围刷新
}
else if(e.button == 2) // 右键则拉框范围设置为主试图显示范围
{
IEnvelope pEnv = axMapControl2.TrackRectangle();
axMapControl1.Extent = pEnv;
axMapControl1.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGraphics, null, null);
}
}
}
/// <summary>
/// 鹰眼视图上鼠标长按拖动事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void axMapControl2_OnMouseMove(object sender, IMapControlEvents2_OnMouseMoveEvent e)
{
if(e.button==1)
{
IPoint pPoint = new PointClass();
pPoint.PutCoords(e.mapX, e.mapY);
axMapControl1.CenterAt(pPoint);
axMapControl1.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGraphics, null, null);
}
}
3.OnExtentUpdated实现
当主视图的视图发生变化时,对应在鹰眼图上用红色框框住显示范围
因为是图层元素的设置,需要在IActiveView
上设置,又需要先清除此时鹰眼图上的元素,需要用到IGraphicsContainer
,而这两个接口都在PageLayout和Map
中被实现,根据COM对象协议,可以利用axMapControl.Map
进行接口转换,得到当前地图对应的ActiveView和IGraphicsContainer
对红色框的获取,通过创建这样的一个IElement
,添加到Map
的IGraphicsContainer
中,再用ActiveView
刷新。
具体的绘制过程可以看下面的代码
/// <summary>
/// 主窗体视图范围变化
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void axMapControl1_OnExtentUpdated(object sender, IMapControlEvents2_OnExtentUpdatedEvent e)
{
// 获取当前地图视图的外包矩形
IEnvelope pEnvelope = (IEnvelope)e.newEnvelope;
// 获得GraphicsContainer对象
IGraphicsContainer pGraphicsContainer = axMapControl2.Map as IGraphicsContainer;
IActiveView pActiveView = pGraphicsContainer as IActiveView;
// 清除对象中的所有图形元素
pGraphicsContainer.DeleteAllElements();
// 获得矩形图形元素
IRectangleElement pRectangleEle = new RectangleElementClass();
IElement pElement = pRectangleEle as IElement;
pElement.Geometry = pEnvelope;
//设置FillShapeElement对象的symbol
IFillShapeElement pFillShapeEle = pElement as IFillShapeElement;
pFillShapeEle.Symbol = getFillSymbol();
// 进行填充
pGraphicsContainer.AddElement((IElement)pFillShapeEle, 0);
// 刷新试图
pActiveView.PartialRefresh(esriViewDrawPhase.esriViewGraphics, null, null);
}
/// <summary>
/// 获得鹰眼视图显示方框的symbol
/// </summary>
/// <returns></returns>
private IFillSymbol getFillSymbol()
{
// 矩形框的边界线颜色
IRgbColor pColor = new RgbColorClass();
pColor.Red = 255;
pColor.Green = 0;
pColor.Blue = 0;
pColor.Transparency = 255;
// 边界线
ILineSymbol pOutline = new SimpleLineSymbolClass();
pOutline.Width = 3;
pOutline.Color = pColor;
// symbol的背景色
pColor = new RgbColorClass();
pColor.Red = 255;
pColor.Green = 0;
pColor.Blue = 0;
pColor.Transparency = 0;
// 获得显示的图形元素
IFillSymbol pFillSymbol = new SimpleFillSymbolClass();
pFillSymbol.Color = pColor;
pFillSymbol.Outline = pOutline;
return pFillSymbol;
}
参考博客
c#鹰眼地图的实现(理解消息传递机制)
ArcGIS Engine 开发 (五)鹰眼功能的实现,将图像元素(element)显示在视图上的步骤