这个例子将引导您创建第一个简单的地图显示程序,并添加基本的缩放和漫游功能。如果您之前没有接触过ArcGIS Engine的开发,那么这个例子是您迈入ArcGIS Engine二次开发大门的极好例子,如果您之前没有接触过C#.NET,也无需担心,这个例子将从零开始引导您一步一步完成任务。
1创建一个新的工程
首先打开Microsoft Visual Studio 2008,点击菜单栏中的“文件”—>“新建”—>“项目”,在弹出的对话框中选择新建一个Visual C#的Windows应用程序,之后更改项目名称为“ZZUMap”,更改文件的路径为个人实习文件夹,点击“确定”即可。
选中项目“ZZUMap”中的窗体“Form1”,修改其Name属性为“MainForm”,Text属性为“ZZUMap”。
2添加控件
选择工具箱中的“菜单和工具栏|MenuStrip”,将其拖入窗体。
选择工具箱中的“ArcGIS Windows Forms”节,将“ToolbarControl”控件拖入窗体,并将其属性中的Dock设置为Top。
选择工具箱中的“菜单和工具栏|StatusStrip”,将其拖入到窗体。
选择工具箱中的“容器|SplitContainer”容器拖入窗体,并将其属性中的Dock设置为Fill。
再将“容器|SplitContainer”容器拖入Panel1,设置为水平拆分方向,并将其属性中的Dock设置为Fill。
将TabControl控件拖入Panel1,将Alignment属性设置为Bottom,Dock属性设置为Fill。点击TabPages属性右边的按钮,弹出TabPage集合编辑器,将tabPage1的Name设置为tabPageLayer,Text设置为图层,将tabPage2的Name设置为tabPageProperty,Text设置为属性。
选择“图层”选项卡,拖入TOCControl控件,设置Dock属性为Fill。
选择“属性”选项卡,拖入PropertyGrid设置Dock属性为Fill。
拖入TabControl控件到第一个SplitContainer容器的Panel2,设置Dock属性为Fill。并上述类似的方法,将两个选项卡的Name和Text分别设置为:(tabPageMap、地图),(tabPageLayout,制版)。
选择“地图”选项卡,拖入MapControl控件,设置Dock属性为Fill。
选择“制版”选项卡,拖入PageLayoutControl控件,设置Dock属性为Fill。
将MapControl控件拖入第二个SplitContainer容器的Panel2,设置Dock属性为Fill。
最后将LicenseControl控件拖入到窗体的任意地方。
按F5编译运行还不能运行,因为就很可能是你的ArcEngine10.0没有许可,因为我的就是这个情况,所以会报错,重新授权下就OK了,解决方法:打开program.cs
把ESRI.ArcGIS.RuntimeManager.Bind(ESRI.ArcGIS.ProductCode.EngineOrDesktop);
这句放到Application.SetCompatibleTextRenderingDefault(false);和Application.Run(new Form1());之间。
3控件绑定
通过以上步骤添加的控件还只是单独存在,而我们的程序需要各控件间协同工作,因此要进行控件绑定。
分别右击ToolbarControl、TOCControl控件,将Buddy设置为axMapControl1,如下图所示。
这样,工具条和图层控件就与地图控件关联了。
4添加工具
此时,工具条中还没有任何工具,添加的方法也很简单。右击ToolbarControl,选择“属性|Items”,点击Add,选择Commands选项卡中的Generic,双击Open、SaveAs、Redo、Undo即可将相应工具添加到工具条。
常见的工具有:
Map Navigation中的导航工具,Map Inquiry中的查询工具,Feature Selection中的选择工具,你可以根据需要酌情添加工具,如下图。
目前为止运行程序界面如下:
5添加菜单
在设计视图中,单击菜单栏,会出现“请在此处键入”的提示,单击提示就可以键入菜单名称,如“文件”,再单击“文件”,即可输入其下拉子菜单。
每创建一个菜单,请在其属性面板中设置 Name 属性,而且不要为中文,因此 Name 值将是此菜单响应函数的函数名的一部分,带中文的函数名,总是不好吧。我们将添加新建( New )、打开( Open )、添加数据( AddData )、保存( Save )、另存为( SaveAs )、退出( Exit )这些菜单,()内为相应的 Name 属性值。
你可以在属性面板中的 Text 属性中,把菜单名设置为中英文形式,如“打开 O pen ”,带下划线的 O 表示此项菜单的快捷键是字母 O ,设置方法是在相应字母前加上“ & ”字符,如“打开 &Open ”。但这种快捷键只在打开此下拉菜单时才有效,即当你单击“文件”菜单弹出下拉菜单时,按下字母 O 就可以定位到“打开”菜单。
还有一种在程序运行时都有效的全局快捷键,可以在属性面板中的“ ShortCutKeys ”中设置。
你还可以在属性面板中的 Image 属性中设置你喜欢的菜单图标。单击 Image 那一行右边的按钮,弹出如下菜单。选择“项目资源文件”,再单击导入就可以选择你的图标了。
最终效果如下所示。
注意,在解决方案面板中,选中刚才添加的所有图标,在其属性面板中将生成操作设置为“嵌入的资源”,这一点很重要!菜单的实现参考ArcEngine自带的模板MapControl Application中的菜单实现。先新建一个类,命名为CreateNewDocument.cs,添加引用:
using ESRI.ArcGIS.ADF.BaseClasses;
using ESRI.ArcGIS.ADF.CATIDs;
using ESRI.ArcGIS.Controls;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.SystemUI;
using System.Windows.Forms;
在构造函数中继承类:
public class CreateNewDocument : BaseCommand;
{
……
}
然后将以下代码复制覆盖到类CreateNewDocument中
private IHookHelper m_hookHelper = null;
//constructor
public CreateNewDocument()
{
//update the base properties
base.m_category = ".NET Application";
base.m_caption = "NewDocument";
base.m_message = "Create a new map";
base.m_toolTip = "Create a new map";
base.m_name = "DotNetTemplate_NewDocumentCommand";
}
#region Overridden Class Methods
/// <summary>
/// Occurs when this command is created
/// </summary>
/// <param name="hook">Instance of the application</param>
public override void OnCreate(object hook)
{
if (m_hookHelper == null)
m_hookHelper = new HookHelperClass();
m_hookHelper.Hook = hook;
}
/// <summary>
/// Occurs when this command is clicked
/// </summary>
public override void OnClick()
{
IMapControl3 mapControl = null;
//get the MapControl from the hook in case the container is a ToolbarControl
if (m_hookHelper.Hook is IToolbarControl)
{
mapControl = (IMapControl3)((IToolbarControl)m_hookHelper.Hook).Buddy;
}
//In case the container is MapControl
else if (m_hookHelper.Hook is IMapControl3)
{
mapControl = (IMapControl3)m_hookHelper.Hook;
}
else
{
MessageBox.Show("Active control must be MapControl!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
return;
}
//check to see if there is an active edit session and whether edits have been made
DialogResult result;
IEngineEditor engineEditor = new EngineEditorClass();
if ((engineEditor.EditState == esriEngineEditState.esriEngineStateEditing) && (engineEditor.HasEdits() == true))
{
result = MessageBox.Show("Would you like to save your edits", "Save Edits", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
switch (result)
{
case DialogResult.Cancel:
return;
case DialogResult.No:
engineEditor.StopEditing(false);
break;
case DialogResult.Yes:
engineEditor.StopEditing(true);
break;
}
}
//allow the user to save the current document
DialogResult res = MessageBox.Show("Would you like to save the current document?", "AoView", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (res == DialogResult.Yes)
{
//launch the save command
ICommand command = new ControlsSaveAsDocCommandClass();
command.OnCreate(m_hookHelper.Hook);
command.OnClick();
}
//create a new Map
IMap map = new MapClass();
map.Name = "Map";
//assign the new map to the MapControl
mapControl.DocumentFilename = string.Empty;
mapControl.Map = map;
}
#endregion
然后定义指针和变量:
privEmpty; ate ESRI.ArcGIS.Controls.IMapControl4 m_mapControl = null;
private ESRI.ArcGIS.Controls.IPageLayoutControl3 m_pageLayoutControl = null;
private string m_mapDocumentName = string.
最后在菜单按钮的事件中填入以下代码:
private void AddData_Click(object sender, EventArgs e)
{
int currentLayerCount = this.axMapControl1.LayerCount;
ICommand pCommand = new ControlsAddDataCommandClass();
pCommand.OnCreate(this.axMapControl1.Object);
pCommand.OnClick();
}
private void Save_Click(object sender, EventArgs e)
{
//execute Save Document command
if (m_mapControl.CheckMxFile(m_mapDocumentName))
{
//create a new instance of a MapDocument
IMapDocument mapDoc = new MapDocumentClass();
mapDoc.Open(m_mapDocumentName, string.Empty);
//Make sure that the MapDocument is not readonly
if (mapDoc.get_IsReadOnly(m_mapDocumentName))
{
MessageBox.Show("Map document is read only!");
mapDoc.Close();
return;
}
}
}
private void SavaAs_Click(object sender, EventArgs e)
{
//execute SaveAs Document command
ICommand command = new ControlsSaveAsDocCommandClass();
command.OnCreate(m_mapControl.Object);
command.OnClick();
}
private void Open_Click(object sender, EventArgs e)
{
//execute Open Document command
ICommand command = new ControlsOpenDocCommandClass();
command.OnCreate(m_mapControl.Object);
command.OnClick();
}
private void Exit_Click(object sender, EventArgs e)
{
//exit the application
Application.Exit();
}
private void New_Click(object sender, EventArgs e)
{
//execute New Document command
ICommand command = new CreateNewDocument();
command.OnCreate(m_mapControl.Object);
command.OnClick();
}
6PageLayout与MapControl联动
在ArcMap程序中,数据视图和布局视图中的数据改变是实时互动的,那是因为它们本来就是在处理同一份数据。将axMapControl1中的Map拷贝到axPageLayoutControl1代码如下:
private voidCopyAndOverwriteMap()
{
//Get IObjectCopy interface
IObjectCopy objectCopy =newObjectCopyClass();
//Get IUnknown interface (map to copy)
object toCopyMap = axMapControl1.Map;
//Get IUnknown interface (copied map)
object copiedMap = objectCopy.Copy(toCopyMap);
//Get IUnknown interface (map to overwrite)
object toOverwriteMap = axPageLayoutControl1.ActiveView.FocusMap;
//Overwrite the PageLayoutControl's map
objectCopy.Overwrite(copiedMap,reftoOverwriteMap);
}
要实现axPageLayoutControl1中的数据与axMapControl1中的数据同步,需要在axMapControl1的以下事件中写入相应的代码:
private voidaxMapControl1_OnMapReplaced(objectsender,
ESRI.ArcGIS.MapControl.IMapControlEvents2_OnMapReplacedEvent e)
{
CopyAndOverwriteMap();
}
private voidaxMapControl1_OnAfterScreenDraw(objectsender,
ESRI.ArcGIS.MapControl.IMapControlEvents2_OnAfterScreenDrawEvent e)
{
//Get IActiveView interface
IActiveView activeView = (IActiveView)
axPageLayoutControl1.ActiveView.FocusMap;
//Get IDisplayTransformation interface
IDisplayTransformation displayTransformation =
activeView.ScreenDisplay.DisplayTransformation;
//Set the visible extent of the focus map
displayTransformation.VisibleBounds = axMapControl1.Extent;
axPageLayoutControl1.ActiveView.Refresh(); //根据MapControl的视图范围,确定PageLayoutControl的视图范围
CopyAndOverwriteMap();
}
private voidaxMapControl1_OnViewRefreshed(objectsender,
ESRI.ArcGIS.MapControl.IMapControlEvents2_OnViewRefreshedEvent e)
{
//axTOCControl1.Update ();
CopyAndOverwriteMap();
}
运行但是axTOCControl控件图层不显示,这是因为还要设置SetBuddyControl,ToolBarControl控件中同样要设置,只需要在在主窗口Load函数中添加下面一句话就可以了
private void MainForm_Load(object sender, EventArgs e)
{
axTOCControl1.SetBuddyControl(axMapControl1);//ADDaxToolbarControl1.SetBuddyControl(m_mapControl);
}
7鹰眼的实现
鹰眼用来显示主窗体当前视图范围在全景视图中的位置,在ArcMap中使用一个线框在鹰眼视图中标识。当主视图中的视图范围改变时,鹰眼中的线框随之改变,当拖动鹰眼视图中的红线框时,主视图中的视图范围也随之改变。
下面开始实现鹰眼功能,添加using ESRI.ArcGIS.Carto、using ESRI.ArcGIS.Geometry、
using ESRI.ArcGIS.Display三个引用。首先在axMapControl1中视图范围改变时鹰眼窗体要做出对应的响应,即绘制线框并显示,在OnExtentUpdated事件中添加代码如下:
private void axMapControl1_OnExtentUpdated (object sender, ESRI.ArcGIS.Controls.IMapControlEvents2_OnExtentUpdatedEvent e)
{
//创建鹰眼中线框
IEnvelope pEnv = (IEnvelope)e.newEnvelope;
IRectangleElement pRectangleEle = new RectangleElementClass();
IElement pEle = pRectangleEle as IElement;
pEle.Geometry = pEnv;
//设置线框的边线对象