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
{
[Guid("f27d8789-fbbc-4801-be78-0e3cd8fff9d5")]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("_sdnMap.Maps")]
public class Maps : IMaps, IDisposable
{
//class member - using internally an ArrayList to manage the Maps collection
private ArrayList m_array = null;
#region class constructor
public Maps()
{
m_array = new ArrayList();
}
#endregion
#region IDisposable Members
/// <summary>
/// Dispose the collection
/// </summary>
public void Dispose()
{
if (m_array != null)
{
m_array.Clear();
m_array = null;
}
}
#endregion
#region IMaps Members
/// <summary>
/// Remove the Map at the given index
/// </summary>
/// <param name="Index"></param>
public void RemoveAt(int Index)
{
if (Index > m_array.Count || Index < 0)
throw new Exception("Maps::RemoveAt:\r\nIndex is out of range!");
m_array.RemoveAt(Index);
}
/// <summary>
/// Reset the Maps array
/// </summary>
public void Reset()
{
m_array.Clear();
}
/// <summary>
/// Get the number of Maps in the collection
/// </summary>
public int Count
{
get
{
return m_array.Count;
}
}
/// <summary>
/// Return the Map at the given index
/// </summary>
/// <param name="Index"></param>
/// <returns></returns>
public IMap get_Item(int Index)
{
if (Index > m_array.Count || Index < 0)
throw new Exception("Maps::get_Item:\r\nIndex is out of range!");
return m_array[Index] as IMap;
}
/// <summary>
/// Remove the instance of the given Map
/// </summary>
/// <param name="Map"></param>
public void Remove(IMap Map)
{
m_array.Remove(Map);
}
/// <summary>
/// Create a new Map, add it to the collection and return it to the caller
/// </summary>
/// <returns></returns>
public IMap Create()
{
IMap newMap = new MapClass();
m_array.Add(newMap);
return newMap;
}
/// <summary>
/// Add the given Map to the collection
/// </summary>
/// <param name="Map"></param>
public void Add(IMap Map)
{
if (Map == null)
throw new Exception("Maps::Add:\r\nNew Map is mot initialized!");
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两种视图的同步工作。
在下一讲中,我将给大家带来的是状态栏的相关操作