原文:《ArcGIS Engine+C#实例开发教程》第三讲 MapControl与PageLayoutControl同步
摘要:在ArcMap中,能够很方面地进行MapView和LayoutView两种视图的切换,而且二者之间的数据是同步显示的。关于两种视图同步的实现方法有多种,可以使用ObjectCopy对象进行数据硬拷贝,而比较简单的方法莫过于二者共享一份地图了,这也是最常用的方法。
教程目录:
第三讲 MapControl与PageLayoutControl同步
------------------------------------------------------------------
在ArcMap中,能够很方面地进行MapView和Layout View两种视图的切换,而且二者之间的数据是同步显示的。
关于两种视图同步的实现方法有多种,可以使用ObjectCopy对象进行数据硬拷贝,而比较简单的方法莫过于二者共享一份地图了,这也是最常用的方法。
1、新建同步类ControlsSynchronizer
在解决方案面板中右击项目名,选择“添加|类”,在类别中选择“Visual C#项目项”,在模板中选择“类”,输入类名“ControlsSynchronizer.cs”,将以下代码覆盖自动生成的代码:
using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.IO; using System.Runtime.InteropServices; using ESRI.ArcGIS.esriSystem; using ESRI.ArcGIS.Carto; using ESRI.ArcGIS.Controls; using ESRI.ArcGIS.SystemUI; namespace _sdnMap private ArrayList m_frameworkControls = null; #region constructor /// <summary> /// <summary> #region properties /// <summary> /// <summary> /// <summary> if (m_IsMapCtrlactive) #region Methods //缓存当前PageLayout的CurrentTool //解除PagleLayout //激活MapControl //将之前MapControl最后使用的tool,作为活动的tool,赋给MapControl的CurrentTool m_IsMapCtrlactive = true; //为每一个的framework controls,设置Buddy control为MapControl /// <summary> //缓存当前MapControl的CurrentTool //解除MapControl //激活PageLayoutControl //将之前PageLayoutControl最后使用的tool,作为活动的tool,赋给PageLayoutControl的CurrentTool m_IsMapCtrlactive = false; //为每一个的framework controls,设置Buddy control为PageLayoutControl /// <summary> if (m_pageLayoutControl == null || m_mapControl == null) //create a new instance of IMaps collection which is needed by the PageLayout bool bIsMapActive = m_IsMapCtrlactive; //call replace map on the PageLayout in order to replace the focus map //assign the new map to the MapControl //reset the active tools //make sure that the last active control is activated /// <summary> m_mapControl = MapControl; this.BindControls(activateMapFirst); /// <summary> //create a new instance of IMap //create a new instance of IMaps collection which is needed by the PageLayout //call replace map on the PageLayout in order to replace the focus map //reset the active tools //make sure that the last active control is activated /// <summary> m_frameworkControls.Add(control); /// <summary> m_frameworkControls.Remove(control); /// <summary> m_frameworkControls.RemoveAt(index); /// <summary> foreach (object obj in m_frameworkControls) |
2、新建Maps类
在同步类中,要用到Maps类,用于管理地图对象。与新建同步类ControlsSynchronizer类似,我们新建一Maps类,其所有代码如下所示:
using System; using System.Collections; using System.Collections.Generic; using System.Text; using System.Runtime.InteropServices; using ESRI.ArcGIS.Carto; namespace _sdnMap #region class constructor #region IDisposable Members /// <summary> #endregion #region IMaps Members /// <summary> m_array.RemoveAt(Index); /// <summary> /// <summary> /// <summary> return m_array[Index] as IMap; /// <summary> /// <summary> return newMap; /// <summary> m_array.Add(Map); #endregion |
3、新建打开文档类OpenNewMapDocument
由于从工具栏自带的打开按钮打开地图文档的时候,不会自动进行两种视图之间的同步,所以我们要自己派生一个OpenNewMapDocument类,用于打开地图文档。
右击项目名,选择“添加|类”,再选择ArcGIS类别中的BaseCommand模板,输入类名为“OpenNewMapDocument.cs”。
首先添加引用:
using System.Windows.Forms; using ESRI.ArcGIS.Carto; |
再添加如下成员变量:
private ControlsSynchronizer m_controlsSynchronizer = null; |
修改默认的构造函数如下所示:
//添加参数 public OpenNewMapDocument(ControlsSynchronizer controlsSynchronizer) { // // TODO: Define values for the public properties // //设定相关属性值 base.m_category = "Generic"; //localizable text base.m_caption = "Open"; //localizable text base.m_message = "This should work in ArcMap/MapControl/PageLayoutControl"; //localizable text base.m_toolTip = "Open"; //localizable text base.m_name = "Generic_Open"; //unique id, non-localizable (e.g. "MyCategory_MyCommand") //初始化m_controlsSynchronizer m_controlsSynchronizer = controlsSynchronizer; try { // // TODO: change bitmap name if necessary // string bitmapResourceName = GetType().Name + ".bmp"; base.m_bitmap = new Bitmap(GetType(), bitmapResourceName); } catch (Exception ex) { System.Diagnostics.Trace.WriteLine(ex.Message, "Invalid Bitmap"); } } |
再在OnClick函数中添加如下代码:
public override void OnClick() { // TODO: Add OpenNewMapDocument.OnClick implementation OpenFileDialog dlg = new OpenFileDialog(); dlg.Filter = "Map Documents (*.mxd)|*.mxd"; dlg.Multiselect = false; dlg.Title = "Open Map Document"; if (dlg.ShowDialog() == DialogResult.OK) { string docName = dlg.FileName; IMapDocument mapDoc = new MapDocumentClass(); if (mapDoc.get_IsPresent(docName) && !mapDoc.get_IsPasswordProtected(docName)) { mapDoc.Open(docName, string.Empty); IMap map = mapDoc.get_Map(0); m_controlsSynchronizer.ReplaceMap(map); mapDoc.Close(); |
在添加类时,模板会自动添加一个名为“OpenNewMapDocument.bmp”的图标,你可以自己修改或者替换为打开的文件夹的图标。
4、两种视图的同步
在3sdnMap.cs中添加成员变量,即同步类对象:
private ControlsSynchronizer m_controlsSynchronizer = null; |
在Form1_Load函数中进行初始化工作:
//初始化controls synchronization calss m_controlsSynchronizer = new ControlsSynchronizer(m_mapControl, m_pageLayoutControl); //把MapControl和PageLayoutControl绑定起来(两个都指向同一个Map),然后设置MapControl为活动的Control m_controlsSynchronizer.BindControls(true); //为了在切换MapControl和PageLayoutControl视图同步,要添加Framework Control m_controlsSynchronizer.AddFrameworkControl(axToolbarControl1.Object); m_controlsSynchronizer.AddFrameworkControl(this.axTOCControl1.Object); // 添加打开命令按钮到工具条 OpenNewMapDocument openMapDoc = new OpenNewMapDocument(m_controlsSynchronizer); axToolbarControl1.AddItem(openMapDoc, -1, 0, false, -1, esriCommandStyles.esriCommandStyleIconOnly); |
因为我们自动派生了打开文档类,并自己将其添加到工具条,所以我们就不需要工具条原来的“打开”按钮了,可以ToolbarControl的属性中将其删除。
下面,我们可完成上一讲遗留的功能了。
/// <summary> /// 新建地图命令 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void New_Click(object sender, EventArgs e) { //询问是否保存当前地图 DialogResult res = MessageBox.Show("是否保存当前地图?", "提示", MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (res == DialogResult.Yes) { //如果要保存,调用另存为对话框 ICommand command = new ControlsSaveAsDocCommandClass(); if (m_mapControl != null) command.OnCreate(m_controlsSynchronizer.MapControl.Object); else command.OnCreate(m_controlsSynchronizer.PageLayoutControl.Object); command.OnClick(); } //创建新的地图实例 IMap map = new MapClass(); map.Name = "Map"; m_controlsSynchronizer.MapControl.DocumentFilename = string.Empty; //更新新建地图实例的共享地图文档 m_controlsSynchronizer.ReplaceMap(map); } |
/// <summary> /// 打开地图文档Mxd命令 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Open_Click(object sender, EventArgs e) { if (this.axMapControl1.LayerCount > 0) { DialogResult result = MessageBox.Show("是否保存当前地图?", "警告", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question); if (result == DialogResult.Cancel) return; if (result == DialogResult.Yes) this.Save_Click(null, null); } OpenNewMapDocument openMapDoc = new OpenNewMapDocument(m_controlsSynchronizer); openMapDoc.OnCreate(m_controlsSynchronizer.MapControl.Object); openMapDoc.OnClick(); } |
在添加数据AddData时,我们也要进行地图共享,故在AddData_Click函数后面添加如下代码:
IMap pMap = this.axMapControl1.Map; this.m_controlsSynchronizer.ReplaceMap(pMap); |
在另存为地图文档时,有可能会丢失数据,因此我们需要提示用户以确认操作,故需修改SaveAs_Click函数,如下所示:
/// <summary> /// 另存为地图文档命令 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void SaveAs_Click(object sender, EventArgs e) { //如果当前视图为MapControl时,提示用户另存为操作将丢失PageLayoutControl中的设置 if (m_controlsSynchronizer.ActiveControl is IMapControl3) { if (MessageBox.Show("另存为地图文档将丢失制版视图的设置\r\n您要继续吗?", "提示",MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No) return; } //调用另存为命令 ICommand command = new ControlsSaveAsDocCommandClass(); command.OnCreate(m_controlsSynchronizer.ActiveControl); command.OnClick(); } |
在切换视图时,我们要激活相关的视图,故在设计视图的属性面板中选择tabControl2控件,再选择事件按钮,找到“SelectedIndexChanged”事件双击添加之。其实现代码如下所示:
/// <summary> /// 切换地图和制版视图 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void tabControl2_SelectedIndexChanged(object sender, EventArgs e) { if (this.tabControl2.SelectedIndex == 0) { //激活MapControl m_controlsSynchronizer.ActivateMap(); } else { //激活PageLayoutControl m_controlsSynchronizer.ActivatePageLayout(); } } |
5、编译运行
按F5编译运行程序,至此我们完成了MapControl和PageLayoutControl两种视图的同步工作。