ArcGIS Engine
更新时间:2024-02-29 07:34:01 阅读量: 综合文库 文档下载
《ArcGIS Engine+C#实例开发教程》第一讲 桌面GIS应用程序框架的建立
本讲主要是使用MapControl、PageLayoutControl、ToolbarControl、TOCControl四个控件建立起基本的桌面GIS应用程序框架。最终成果预览如下:
1、新建项目
启动VS2005,选择“文件|新建|项目”,在项目类型中选择Visual C#,再选择Windows应用程序模板,输入名称“3sdnMap”,点击确定。
在解决方案管理器中将“Form1.cs”重命名为“3sdnMap.cs”,在设计视图中,选中窗体,将其属性中的“Text”改为“3sdnMap”。 2、添加控件
选择工具箱中的“菜单和工具栏|MenuStrip”,将其拖入窗体。 选择工具箱中的“ArcGIS Windows Forms”节,将“ToolbarControl”控件拖入窗体,并将其属性中的Dock设置为Top。 选择工具箱中的“菜单和工具栏|StatusStrip”,将其拖入到窗体。
选择工具箱中的“容器|SplitContainer”容器拖入窗体,并将其属性中的Dock设置为Fill。
将TabControl控件拖入Panel1,将Alignment属性设置为Bottom,Dock属性设置为Fill。点击TabPages属性右边的按钮,弹出TabPage集合编辑器,将tabPage1的Name设置为tabPageLayer,Text设置为图层,将tabPage2的Name设置为tabPageProperty,Text设置为属性。如下所示。
选择“图层”选项卡,拖入TOCControl控件,设置Dock属性为Fill。 选择“属性”选项卡,拖入DataGridView控件,设置Dock属性为Fill。
拖入TabControl控件到Panel2,设置Dock属性为Fill。并上述类似的方法,将两个选项卡的Name和Text分别设置为:(tabPageMap、地图),(tabPageLayout,制版)。
选择“地图”选项卡,拖入MapControl控件,设置Dock属性为Fill。
选择“制版”选项卡,拖入PageLayoutControl控件,设置Dock属性为Fill。 最后将LicenseControl控件拖入到窗体的任意地方。 按F5编译运行,可以看到刚才布局好的程序界面了。 3、控件绑定
通过以上步骤添加的控件还只是单独存在,而我们的程序需要各控件间协同工作,因此要进行控件绑定。 分别右击ToolbarControl、TOCControl控件,将Buddy设置为axMapControl1,如下图所示。
这样,工具条和图层控件就与地图控件关联了。 4、添加工具
此时,工具条中还没有任何工具,添加的方法也很简单。右击ToolbarControl,选择“属性|Items”,点击Add,选择Commands选项卡中的Generic,双击Open、SaveAs、Redo、Undo即可将相应工具添加到工具条。
常见的工具有:
Map Navigation中的导航工具,Map Inquiry中的查询工具,Feature Selection中的选择工具,你可以根据需要酌情添加工具。 5、编译运行
按F5即可编译运行程序,至此桌面GIS应用程序框架基本框架已经搭建好了,你可以通过工具条的工具打开地图文档,浏览地图了,效果如开篇所示。
《ArcGIS Engine+C#实例开发教程》第二讲 菜单的添加及其实现
在上一讲中,我们实现了应用程序基本框架,其中有个小错误,在此先跟大家说明下。在“属性”选项卡中,我们当时添加的是 DataGridView 控件,这个控件是用来显示数据表的,而专门用于属性的查询和设置的控件是 PropertyGrid 控件。因此请你删除“属性”选项卡中的 DataGridView 控件,再把位于“工具箱 | 所有 Windows 窗体 |PropertyGrid ”(如果没有,右击选择“选择项”以添加此控件)控件拖到该选项卡。
在这一讲中,主要讲解菜单的添加和实现。 1、 添加菜单
在设计视图中,单击菜单栏,会出现“请在此处键入”的提示,单击提示就可以键入菜单名称,如“文件”,再单击“文件”,即可输入其下拉子菜单,如下所示:
Tips :
每创建一个菜单,请在其属性面板中设置 Name 属性,而且不要为中文,因此 Name 值将是此菜单响应函数的函数名的一部分,带中文的函数名,总是不好吧。 本讲中,我们将添加新建( New )、打开( Open )、添加数据( AddData )、保存( Save )、另存为( SaveAs )、退出( Exit )这些菜单,()内为相应的 Name 属性值。 Tips:
你可以在属性面板中的 Text 属性中,把菜单名设置为中英文形式,如“打开 O pen ”,带下划线的 O 表示此项菜单的快捷键是字母 O ,设置方法是在相应字母前加上“ & ”字符,如“打开 &Open ”。但这种快捷键只在打开此下拉菜单时才有效,即当你单击“文件”菜单弹出下拉菜单时,按下字母 O 就可以定位到“打开”菜单。 还有一种在程序运行时都有效的全局快捷键,可以在属性面板中的“ ShortCutKeys ”中设置。
你还可以在属性面板中的 Image 属性中设置你喜欢的菜单图标。单击 Image 那一行右边的按钮,弹出如下菜单。选择“项目资源文件”,再单击导入就可以选择你的图标了。
最终效果如下所示。
注意,在解决方案面板中,选中刚才添加的所有图标,在其属性面板中将生成操作设置为“嵌入的资源”,这一点很重要!
2、 实现相关菜单
首先定义指针(写在 public partial class Form1 : Form 下面即可): private ESRI.ArcGIS.Controls.IMapControl3 m_mapControl = null;
private ESRI.ArcGIS.Controls.IPageLayoutControl2 m_pageLayoutControl = null; private IMapDocument pMapDocument;
若以上指针无效,请添加以下引用: using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Controls; using ESRI.ArcGIS.esriSystem; using ESRI.ArcGIS.Display; using ESRI.ArcGIS.Geometry; using ESRI.ArcGIS.SystemUI;
在设计视图中的属性面板中,选择 Form1 ,即主窗体,单击事件按钮(闪电形状的那个按钮),打到“ Load ”事件并双击,添加此事件。
在 Form1_Load 函数中初始化这些指针:
// 取得 MapControl 和 PageLayoutControl 的引用
m_mapControl = (IMapControl3)this.axMapControl1.Object;
m_pageLayoutControl = (IPageLayoutControl2)this.axPageLayoutControl1.Object; 依次双击每个菜单项,添加菜单响应函数。实现代码如下: ///
/// 新建地图命令 ///
///
private void New_Click(object sender, EventArgs e) {
// 本命令涉及到 MapControl 和 PageLayoutControl 同步问题,将在下一讲中实现 }
///
/// 打开地图文档 Mxd 命令 ///
///
private void Open_Click(object sender, EventArgs e) {
// 本命令涉及到 MapControl 和 PageLayoutControl 同步问题,将在下一讲中实现 }
///
///
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) {
// 首先确认当前地图文档是否有效 if (null != m_pageLayoutControl.DocumentFilename m_mapControl.CheckMxFile(m_pageLayoutControl.DocumentFilename)) {
// 创建一个新的地图文档实例
IMapDocument mapDoc = new MapDocumentClass(); // 打开当前地图文档
mapDoc.Open(m_pageLayoutControl.DocumentFilename, string.Empty); // 用 PageLayout 中的文档替换当前文档中的 PageLayout 部分
mapDoc.ReplaceContents((IMxdContents)m_pageLayoutControl.PageLayout); // 保存地图文档
mapDoc.Save(mapDoc.UsesRelativePaths, false); mapDoc.Close(); } }
///
/// 另存为地图文档命令 ///
///
private void SaveAs_Click(object sender, EventArgs e) {
&&
// 调用另存为命令
ICommand command = new ControlsSaveAsDocCommandClass(); command.OnCreate(m_controlsSynchronizer.ActiveControl); command.OnClick(); }
///
///
private void Exit_Click(object sender, EventArgs e) {
Application.Exit(); }
3、 编译运行
按 F5 编译运行程序。也许你会发现,菜单命令的实现方式都是类型的。没错,在 AE9.2 中,内置了许多常用的 Command 和 Tool ,如 ControlsAddDataCommandClass 、 ControlsMapZoomInToolClass 、 ControlsMapPanToolClass 等等,这些内置对象在 ESRI.ArcGIS.Controls 命名空间中,你可以对象浏览器中查看。而且这些内置对象的调用方式都类似,如下所示: // 定义
ICommand command = new ControlsSaveAsDocCommandClass(); // 创建
command.OnCreate(m_controlsSynchronizer.ActiveControl); // 调用
command.OnClick();
希望你可以举一反三,去实现更多的你想要的功能。
在下一讲中,我将给大家带来的是 MapControl 与 PageLayoutControl 两种视图同步的实现,
《ArcGIS Engine+C#实例开发教程》第三讲 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 {
///
/// This class is used to synchronize a gven PageLayoutControl and a MapControl.
/// When initialized, the user must pass the reference of these control to the class, bind /// the control together by calling 'BindControls' which in turn sets a joined Map referenced /// by both control; and set all the buddy controls joined between these two controls.
/// When alternating between the MapControl and PageLayoutControl, you should activate the visible control /// and deactivate the other by calling ActivateXXX.
/// This calss is limited to a situation where the controls are not simultaneously visible. ///
public class ControlsSynchronizer {
#region class members
private IMapControl3 m_mapControl = null;
private IPageLayoutControl2 m_pageLayoutControl = null; private ITool m_mapActiveTool = null;
private ITool m_pageLayoutActiveTool = null; private bool m_IsMapCtrlactive = true;
private ArrayList m_frameworkControls = null; #endregion
#region constructor
///
/// 默认构造函数 ///
public ControlsSynchronizer() {
//初始化ArrayList
m_frameworkControls = new ArrayList(); }
///
/// 构造函数 ///
///
///
public ControlsSynchronizer(IMapControl3 mapControl, IPageLayoutControl2 pageLayoutControl) : this() {
//为类成员赋值
m_mapControl = mapControl;
m_pageLayoutControl = pageLayoutControl; }
#endregion
#region properties ///
/// 取得或设置MapControl ///
public IMapControl3 MapControl {
get { return m_mapControl; } set { m_mapControl = value; } }
///
/// 取得或设置PageLayoutControl ///
public IPageLayoutControl2 PageLayoutControl {
get { return m_pageLayoutControl; } set { m_pageLayoutControl = value; } }
///
/// 取得当前ActiveView的类型 ///
public string ActiveViewType {
get {
if (m_IsMapCtrlactive)
return \ else
return \ } }
///
/// 取得当前活动的Control ///
public object ActiveControl {
get {
if (m_mapControl == null || m_pageLayoutControl == null)
throw new Exception(\MapControl PageLayoutControl are not initialized!\
if (m_IsMapCtrlactive)
return m_mapControl.Object; else
return m_pageLayoutControl.Object; } }
#endregion
#region Methods ///
/// 激活MapControl并解除the PagleLayoutControl ///
public void ActivateMap() {
try {
if (m_pageLayoutControl == null || m_mapControl == null)
throw new Exception(\MapControl PageLayoutControl are not initialized!\
//缓存当前PageLayout的CurrentTool if (m_pageLayoutControl.CurrentTool != null) m_pageLayoutActiveTool m_pageLayoutControl.CurrentTool;
//解除PagleLayout
m_pageLayoutControl.ActiveView.Deactivate(); //激活MapControl
m_mapControl.ActiveView.Activate(m_mapControl.hWnd);
//将之前MapControl最后使用的tool,作为活动的tool,赋给MapControl的CurrentTool if (m_mapActiveTool != null) m_mapControl.CurrentTool = m_mapActiveTool;
or
or
=
m_IsMapCtrlactive = true;
//为每一个的framework controls,设置Buddy control为MapControl this.SetBuddies(m_mapControl.Object); }
catch (Exception ex) {
throw new Exception(string.Format(\ } }
///
/// 激活PagleLayoutControl并减活MapCotrol ///
public void ActivatePageLayout() {
try {
if (m_pageLayoutControl == null || m_mapControl == null)
throw new Exception(\MapControl or PageLayoutControl are not initialized!\
//缓存当前MapControl的CurrentTool
if (m_mapControl.CurrentTool != null) m_mapActiveTool = m_mapControl.CurrentTool;
//解除MapControl
m_mapControl.ActiveView.Deactivate();
//激活PageLayoutControl
m_pageLayoutControl.ActiveView.Activate(m_pageLayoutControl.hWnd);
//将之前PageLayoutControl最后使用的tool,作为活动的tool,赋给PageLayoutControl的CurrentTool
if (m_pageLayoutActiveTool != null) m_pageLayoutControl.CurrentTool = m_pageLayoutActiveTool;
m_IsMapCtrlactive = false;
//为每一个的framework controls,设置Buddy control为PageLayoutControl this.SetBuddies(m_pageLayoutControl.Object); }
catch (Exception ex) {
throw new Exception(string.Format(\ } }
///
/// 给予一个地图, 置换PageLayoutControl和MapControl的focus map ///
///
if (newMap == null)
throw new Exception(\map for replacement is not initialized!\
if (m_pageLayoutControl == null || m_mapControl == null) throw new Exception(\MapControl or PageLayoutControl are not initialized!\
//create a new instance of IMaps collection which is needed by the PageLayout //创建一个PageLayout需要用到的,新的IMaps collection的实例 IMaps maps = new Maps();
//add the new map to the Maps collection
//把新的地图加到Maps collection里头去 maps.Add(newMap);
bool bIsMapActive = m_IsMapCtrlactive;
//call replace map on the PageLayout in order to replace the focus map
//we must call ActivatePageLayout, since it is the control we call 'ReplaceMaps'
//调用PageLayout的replace map来置换focus map
//我们必须调用ActivatePageLayout,因为它是那个我们可以调用\的Control this.ActivatePageLayout();
m_pageLayoutControl.PageLayout.ReplaceMaps(maps);
//assign the new map to the MapControl //把新的地图赋给MapControl m_mapControl.Map = newMap;
//reset the active tools
//重设active tools
m_pageLayoutActiveTool = null; m_mapActiveTool = null;
//make sure that the last active control is activated //确认之前活动的control被激活 if (bIsMapActive) {
this.ActivateMap();
m_mapControl.ActiveView.Refresh(); } else {
this.ActivatePageLayout();
m_pageLayoutControl.ActiveView.Refresh(); } }
///
/// bind the MapControl and PageLayoutControl together by assigning a new joint focus map
/// 指定共同的Map来把MapControl和PageLayoutControl绑在一起 ///
///
///
///
public void BindControls(IMapControl3 mapControl, IPageLayoutControl2 pageLayoutControl, bool activateMapFirst) {
if (mapControl == null || pageLayoutControl == null) throw new Exception(\MapControl or PageLayoutControl are not initialized!\
m_mapControl = MapControl;
m_pageLayoutControl = pageLayoutControl;
this.BindControls(activateMapFirst); }
///
/// bind the MapControl and PageLayoutControl together by assigning a new joint focus map /// 指定共同的Map来把MapControl和PageLayoutControl绑在一起 ///
///
public void BindControls(bool activateMapFirst) {
if (m_pageLayoutControl == null || m_mapControl == null) throw new Exception(\MapControl or PageLayoutControl are not initialized!\
//create a new instance of IMap
//创造IMap的一个实例
IMap newMap = new MapClass(); newMap.Name = \
//create a new instance of IMaps collection which is needed by the PageLayout //创造一个新的IMaps collection的实例,这是PageLayout所需要的 IMaps maps = new Maps();
//add the new Map instance to the Maps collection //把新的Map实例赋给Maps collection maps.Add(newMap);
//call replace map on the PageLayout in order to replace the focus map //调用PageLayout的replace map来置换focus map m_pageLayoutControl.PageLayout.ReplaceMaps(maps);
//assign the new map to the MapControl //把新的map赋给MapControl m_mapControl.Map = newMap;
//reset the active tools
//重设active tools
m_pageLayoutActiveTool = null; m_mapActiveTool = null;
//make sure that the last active control is activated
//确定最后活动的control被激活 if (activateMapFirst) this.ActivateMap(); else
this.ActivatePageLayout(); }
///
///by passing the application's toolbars and TOC to the synchronization class, it saves you the
///management of the buddy control each time the active control changes. This method ads the framework ///control to an array; once the active control changes, the class iterates through the array and ///calles SetBuddyControl on each of the stored framework control. ///
///
public void AddFrameworkControl(object control) {
if (control == null)
throw new Exception(\control is not initialized!\
m_frameworkControls.Add(control); }
///
/// Remove a framework control from the managed list of controls ///
///
public void RemoveFrameworkControl(object control) {
if (control == null)
throw new Exception(\not initialized!\
m_frameworkControls.Remove(control); }
///
/// Remove a framework control from the managed list of controls by specifying its index in the list ///
///
public void RemoveFrameworkControlAt(int index) {
if (m_frameworkControls.Count < index)
throw new Exception(\
m_frameworkControls.RemoveAt(index); }
///
/// when the active control changes, the class iterates through the array of the framework controls /// and calles SetBuddyControl on each of the controls. ///
///
try {
if (buddy == null)
throw new Exception(\Buddy Control is not initialized!\
foreach (object obj in m_frameworkControls) {
if (obj is IToolbarControl) {
((IToolbarControl)obj).SetBuddyControl(buddy); }
else if (obj is ITOCControl) {
((ITOCControl)obj).SetBuddyControl(buddy); } } }
catch (Exception ex) {
throw new Exception(string.Format(\ } }
#endregion } }
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(\ [ClassInterface(ClassInterfaceType.None)] [ProgId(\
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
///
/// Dispose the collection /// public void Dispose() {
if (m_array != null) {
m_array.Clear(); m_array = null; } }
#endregion
#region IMaps Members
///
/// Remove the Map at the given index ///
///
if (Index > m_array.Count || Index < 0)
throw new Exception(\
m_array.RemoveAt(Index); }
///
/// Reset the Maps array /// public void Reset() {
m_array.Clear(); }
///
/// Get the number of Maps in the collection /// public int Count {
get {
return m_array.Count; } }
///
/// Return the Map at the given index ///
///
public IMap get_Item(int Index) {
if (Index > m_array.Count || Index < 0)
throw new Exception(\
return m_array[Index] as IMap; }
///
/// Remove the instance of the given Map ///
///
m_array.Remove(Map); }
///
/// Create a new Map, add it to the collection and return it to the caller ///
///
IMap newMap = new MapClass(); m_array.Add(newMap);
return newMap; }
///
/// Add the given Map to the collection ///
///
if (Map == null)
throw new Exception(\
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 = \ base.m_caption = \ //localizable text
base.m_message = \ //localizable text base.m_toolTip = \ //localizable text
base.m_name = \ //unique id, non-localizable (e.g. \
//初始化m_controlsSynchronizer
m_controlsSynchronizer = controlsSynchronizer; try {
//
// TODO: change bitmap name if necessary //
string bitmapResourceName = GetType().Name + \
base.m_bitmap = new Bitmap(GetType(), bitmapResourceName); }
catch (Exception ex) {
System.Diagnostics.Trace.WriteLine(ex.Message, \ } }
再在OnClick函数中添加如下代码:
public override void OnClick() {
// TODO: Add OpenNewMapDocument.OnClick implementation OpenFileDialog dlg = new OpenFileDialog(); dlg.Filter = \ dlg.Multiselect = false;
dlg.Title = \
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的属性中将其删除。 下面,我们可完成上一讲遗留的功能了。
///
/// 新建地图命令 ///
///
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 = \
m_controlsSynchronizer.MapControl.DocumentFilename = string.Empty; //更新新建地图实例的共享地图文档 m_controlsSynchronizer.ReplaceMap(map); }
///
/// 打开地图文档Mxd命令 ///
///
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函数,如下所示:
///
/// 另存为地图文档命令 ///
///
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”事件双击添加之。其实现代码如下所示:
///
/// 切换地图和制版视图 ///
///
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两种视图的同步工作。 在下一讲中,我将给大家带来的是状态栏的相关操作,敬请关注3SDN.NET。
《ArcGIS Engine+C#实例开发教程》第四讲 状态栏信息的添加与实现
在上一讲中,我们完成了 MapControl 和 PageLayoutControl 两种视图的同步工作,本讲我们将完成状态栏信息的添加与实现。
应用程序的状态栏一般用来显示程序的当前状态,当前所使用的工具。 GIS 应用程序一般也在状态栏显示当前光标的坐标、比例尺等信息。
学习完本讲内容,您将学会状态栏编程的基本方法,并且能够在我们的程序的状态栏中添加且显示以下信息:
当前所用工具信息 当前比例尺 当前坐标
1、 添加状态栏项目
在设计视图中,点击窗体中的状态栏,在其属性面板中找到“ Items ”项,单击其右边的按钮,在下拉框中选择“ StatusLabel ”,单击“添加按钮”,依次添加四个 StatusLabel ,依次修改属性参数如下表所示: 序号 1 2 3 4 Name 属性 MessageLabel Blank ScaleLabel CoordinateLabel Text 属性 就绪 比例尺 当前坐标 Spring 属性 False True False False 说明 当前所用工具信息 占位 当前比例尺 当前坐标 设置好之后如下图所示:
Tips :
我们设计出的状态栏最终如下所示: 就绪 ( Blank ) 比例尺 当前坐标 Spring 属性表示可以按状态栏剩余空间自动伸缩。所以加入 Blank 项目,只是为了占个位子,以达到 ScaleLabel 和 CoordinateLabel 项目右对齐而 MessageLabel 项目左对齐的目的。
2、 显示当前所用工具信息
首先添加 axToolbarControl1 的 OnMouseMove 事件 ( 相信大家看了以上的教程,已经知道怎么添加事件了吧,还不知道的建议再温习下前几讲的内容 ) 。在其事件响应函数代码如下:
private void axToolbarControl1_OnMouseMove(object sender, IToolbarControlEvents_OnMouseMoveEvent e) {
// 取得鼠标所在工具的索引号
int index = axToolbarControl1.HitTest(e.x, e.y, false);
if (index != -1) {
// 取得鼠标所在工具的 ToolbarItem
IToolbarItem toolbarItem = axToolbarControl1.GetItem(index);
// 设置状态栏信息
MessageLabel.Text = toolbarItem.Command.Message; }
else {
MessageLabel.Text = \就绪 \ } }
3、 显示当前比例尺
添加 axMapControl1 的 OnMouseMove 事件,其代码如下:
private void axMapControl1_OnMouseMove(object sender, IMapControlEvents2_OnMouseMoveEvent e) {
// 显示当前比例尺
ScaleLabel.Text = \比例尺 1:\ }
4、 显示当前坐标
显示当前坐标也是 axMapControl1 的 OnMouseMove 事件中响应,故只要在 axMapControl1_OnMouseMove 函数中添加如下代码即可:
// 显示当前坐标
CoordinateLabel.Text = \当前坐标 X = \+ e.mapX.ToString() + \Y = \+ e.mapY.ToString() + \\+ this.axMapControl1.MapUnits;
按 F5 编译运行,可以看到,我们的程序已经能够正常工作了。但是细心的你可能会发现,当前坐标的后面的坐标单位为“ esriUnknownUnits ”或“ esriMeters ”之类,即系统在正常单位的前面加上了“ esri ”,追求完美的我们自然看得不舒服。那就进行简单的替换吧。
首先定义个全局坐标单位变量 sMapUnits ,如下所示:
private string sMapUnits;
再 Form1_Load 函数中进行初始化:
sMapUnits = \
添加 axMapControl1 控件的 OnMapReplaced 事件,在事件响应函数中进行坐标单位替换,代码如下:
private void axMapControl1_OnMapReplaced(object sender, IMapControlEvents2_OnMapReplacedEvent e) {
esriUnits mapUnits = axMapControl1.MapUnits;
switch (mapUnits) {
case esriUnits.esriCentimeters:
sMapUnits = \
break;
case esriUnits.esriDecimalDegrees:
sMapUnits = \
break;
case esriUnits.esriDecimeters:
sMapUnits = \
break;
case esriUnits.esriFeet:
sMapUnits = \
break;
case esriUnits.esriInches:
sMapUnits = \
break;
case esriUnits.esriKilometers:
sMapUnits = \
break;
case esriUnits.esriMeters:
sMapUnits = \
break;
case esriUnits.esriMiles:
sMapUnits = \
break;
case esriUnits.esriMillimeters:
sMapUnits = \
break;
case esriUnits.esriNauticalMiles:
sMapUnits = \
break;
case esriUnits.esriPoints:
sMapUnits = \
break;
case esriUnits.esriUnknownUnits:
sMapUnits = \
break;
case esriUnits.esriYards:
sMapUnits = \
break; } }
5、 编译运行
按 F5 编译运行程序。如果你足够细心的话,相信你已经成功了!
在本讲中,介绍中 StatusStrip 控件的基本使用方法和 AE 中当所用工具信息、当前比例尺和当前坐标的显示调用方法。
在下一讲,我将给大家带来的是激动人心的鹰眼功能的实现,
《ArcGIS Engine+C#实例开发教程》第五讲 鹰眼的实现
在上一讲中,我们实现了状态栏的相关信息显示,在这一讲中我们将要实现鹰眼功能。
所谓的鹰眼,就是一个缩略地图,上面有一个矩形框,矩形框区域就是当前显示的地图区域,拖动矩形框可以改变当前地图显示的位置,改变矩形框的大小,可以改变当前地图的显示区域大小,从起到导航的作用。鹰眼是地图浏览中常用的功能之一。
关于鹰眼的实现方式,最常用的是用一个 MapControl 控件显示地图全图,并在上面画一个红色矩形框表示当前地图的显示范围,并实现鹰眼 MapControl 与主窗体的 MapControl 互动。本讲最终效果如下所示:
1 、添加鹰眼控件
由于本教程在第一讲中没有预先考虑到鹰眼所放的位置,故我们要先稍微调整一下程序框架,并添加一个 MapControl 用于显示鹰眼。
在本教程中,我们将鹰眼放在图层控件的下方,调整方法如下:
( 1 )在设计视图中,选择 tabControl1 控件,即放图层和属性的那个容器,将其 Dock 属性设为 None ,并用鼠标拖拽将其缩小。把工具箱中的 SplitContainer 控件拖到窗体的左窗格,即放在 tabControl1 控件的旁边。并将其 Orientation 属性设置为 Horizontal 。
( 2 )选中 tabControl1 控件,按 Ctrl+X 剪切,再选中刚才粘贴到 SplitContainer2 的 Panel1 中,如图 2 所示。操作完成后效果如图 3 所示。
图 2
图 3
( 3 )再选中 SplitContainer2 控件(如果不好选中,直接以属性面板中选择 SplitContainer2 ),将其 Dock 属性设置为 Fill 。再选中 tabControl1 ,将其 Dock 属性也设置为 Fill 。
( 4 )从工具箱中选择 MapControl 控件并拖到 SplitContainer2 的 Panel2 ,作为鹰眼控件。最终效果如图 4 所示。
图 4
2 、鹰眼的实现
( 1 )载入地图到鹰眼控件
当地图载入到主 Map 控件时,同时也载入到鹰眼控件,在 axMapControl1_OnMapReplaced 事件响应函数(此函数上一讲中已经添加了)中添加如下代码:
private void axMapControl1_OnMapReplaced(object sender, IMapControlEvents2_OnMapReplacedEvent e) {
// 前面代码省略
// 当主地图显示控件的地图更换时,鹰眼中的地图也跟随更换
this.axMapControl2.Map = new MapClass();
// 添加主地图控件中的所有图层到鹰眼控件中
for (int i = 1; i <= this.axMapControl1.LayerCount; i++) {
this.axMapControl2.AddLayer(this.axMapControl1.get_Layer(this.axMapControl1.LayerCount - i)); }
// 设置 MapControl 显示范围至数据的全局范围
this.axMapControl2.Extent = this.axMapControl1.FullExtent;
// 刷新鹰眼控件地图
this.axMapControl2.Refresh(); }
( 2 )绘制鹰眼矩形框
为鹰眼控件 MapControl1 添加 OnExtentUpdated 事件,此事件是在主 Map 控件的显示范围改变时响应,从而相应更新鹰眼控件中的矩形框。其响应函数代码如下:
private void axMapControl1_OnExtentUpdated(object sender, IMapControlEvents2_OnExtentUpdatedEvent e) {
// 得到新范围
IEnvelope pEnv = (IEnvelope)e.newEnvelope;
IGraphicsContainer pGra = axMapControl2.Map as IGraphicsContainer;
IActiveView pAv = pGra as IActiveView;
// 在绘制前,清除 axMapControl2 中的任何图形元素
pGra.DeleteAllElements();
IRectangleElement pRectangleEle = new RectangleElementClass();
IElement pEle = pRectangleEle as IElement;
pEle.Geometry = pEnv;
// 设置鹰眼图中的红线框
IRgbColor pColor = new RgbColorClass();
pColor.Red = 255;
pColor.Green = 0;
pColor.Blue = 0;
pColor.Transparency = 255;
// 产生一个线符号对象
ILineSymbol pOutline = new SimpleLineSymbolClass();
pOutline.Width = 2;
pOutline.Color = pColor;
// 设置颜色属性
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;
IFillShapeElement pFillShapeEle = pEle as IFillShapeElement;
pFillShapeEle.Symbol = pFillSymbol;
pGra.AddElement((IElement)pFillShapeEle, 0);
// 刷新
pAv.PartialRefresh(esriViewDrawPhase.esriViewGraphics, null, null); }
( 3 )鹰眼与主 Map 控件互动
为鹰眼控件 MapControl2 添加 OnMouseDown 事件,代码如下:
private void axMapControl2_OnMouseDown(object sender, IMapControlEvents2_OnMouseDownEvent e) {
if (this.axMapControl2.Map.LayerCount != 0) {
// 按下鼠标左键移动矩形框
if (e.button == 1) {
IPoint pPoint = new PointClass();
pPoint.PutCoords(e.mapX, e.mapY);
IEnvelope pEnvelope = this.axMapControl1.Extent;
pEnvelope.CenterAt(pPoint);
this.axMapControl1.Extent = pEnvelope;
this.axMapControl1.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeography, null, null); }
// 按下鼠标右键绘制矩形框
else if (e.button == 2) {
IEnvelope pEnvelop = this.axMapControl2.TrackRectangle();
this.axMapControl1.Extent = pEnvelop;
this.axMapControl1.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeography, null, null); } } }
为鹰眼控件 MapControl2 添加 OnMouseMove 事件,主要实现按下鼠标左键的时候移动矩形框,同时也改变主的图控件的显示范围。代码如下:
private void axMapControl2_OnMouseMove(object sender, IMapControlEvents2_OnMouseMoveEvent e) {
// 如果不是左键按下就直接返回
if (e.button != 1) return;
IPoint pPoint = new PointClass();
pPoint.PutCoords(e.mapX, e.mapY);
this.axMapControl1.CenterAt(pPoint);
this.axMapControl1.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeography, null, null); }
1、 编译运行
按 F5 编译运行程序。
期待的鹰眼功能你已经实现了,按下左键在鹰眼窗口中移动,或者按下右键在鹰眼窗口中画一个矩形,主地图窗口的显示范围都会跟着变化。主地图窗口中的地图经放大缩小等操作后,鹰眼窗口的矩形框大小也会随着改变。
另外,本教程一至五讲的源码已经上传,需要的到3SDN源码下载栏目下载。
在下一讲中,我将给大家带的是 TOCControl 控件右键菜单的实现,敬请关注 3SDN.Net 。
ArcGIS Engine+C#实例开发教程》第六讲 右键菜单添加与实现
在上一讲中,我们完成了鹰眼功能,在这一讲中,大家将实现TOCControl控件和主地图控件的右键菜单。
在AE开发中,右键菜单有两种实现方式,一是使用VS2005自带的ContextMenuStrip控件,二是用AE封装的IToolbarMenu接口。相比较而言,后者更为简单实用,本文采用后者的实现方法。
1、创建右键菜单
在Form1类里面添加如下变量的定义:
//TOCControl控件变量
private ITOCControl2 m_tocControl = null;
//TOCControl中Map菜单
private IToolbarMenu m_menuMap = null;
//TOCControl中图层菜单
private IToolbarMenu m_menuLayer = null;
在Form1_Load函数进行初始化,即菜单的创建:
m_menuMap = new ToolbarMenuClass();
m_menuLayer = new ToolbarMenuClass();
2、添加菜单项
第1步中创建的菜单可认为是菜单容器,里面什么都没有,具体的命令或工具作为菜单项添加到菜单容器才能工作。一般情况下,启动程序就要完成菜单项的添加,故此工作在Form1_Load函数完成。
当然,添加菜单项之前,必须实现相应命令或工具。这里的命令或工具可以AE内置的也可以是自定义的。AE内置了许多可以直接调用的常用命令和工具,如ControlsAddDataCommandClass,在ESRI.ArcGIS.Controls命名空间中,大家可以对象浏览器中查看。当然,这里也可以直接调用AE内置的菜单,如ControlsFeatureSelectionMenu。另外,本讲也实现三自定义命令,以做示范。它们分别为图层可视控制命令(用于控制图层显示与否)、移除图层和放大到整个图层命令。实现方法也很简单,就是右击3sdnMap项目,选择“添加|类”,选择C#普通的类模板,用以下代码覆盖系统自己生成的所有代码。
图层可视控制类LayerVisibility代码:
using ESRI.ArcGIS.ADF.BaseClasses; using ESRI.ArcGIS.Controls;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.SystemUI;
namespace _sdnMap {
///
/// 图层可视控制
///
public sealed class LayerVisibility : BaseCommand, ICommandSubType
{
private IHookHelper m_hookHelper = new HookHelperClass();
private long m_subType;
public LayerVisibility()
{
}
public override void OnClick()
{
for (int i=0; i <= m_hookHelper.FocusMap.LayerCount - 1; i++)
{
if (m_subType == 1) m_hookHelper.FocusMap.get_Layer(i).Visible = true;
if (m_subType == 2) m_hookHelper.FocusMap.get_Layer(i).Visible = false;
}
m_hookHelper.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeography,null,null);
}
public override void OnCreate(object hook)
{
m_hookHelper.Hook = hook;
}
public int GetCount()
{
return 2;
}
public void SetSubType(int SubType)
{
m_subType = SubType;
}
public override string Caption
{
get
{
if (m_subType == 1) return \
else return \
}
}
public override bool Enabled
{
get
{
bool enabled = false; int i;
if (m_subType == 1)
{
for (i=0;i<=m_hookHelper.FocusMap.LayerCount - 1;i++)
{
if (m_hookHelper.ActiveView.FocusMap.get_Layer(i).Visible == false)
{
enabled = true;
break;
}
}
}
else
{
for (i=0;i<=m_hookHelper.FocusMap.LayerCount - 1;i++)
{
if (m_hookHelper.ActiveView.FocusMap.get_Layer(i).Visible == true)
{
enabled = true;
break;
}
}
}
return enabled;
}
}
} }
移除图层类RemoveLayer代码:
using ESRI.ArcGIS.ADF.BaseClasses; using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Controls;
namespace _sdnMap {
///
/// 删除图层
///
public sealed class RemoveLayer : BaseCommand
{
private IMapControl3 m_mapControl;
public RemoveLayer()
{
base.m_caption = \
}
public override void OnClick()
{
ILayer layer = (ILayer)m_mapControl.CustomProperty;
m_mapControl.Map.DeleteLayer(layer);
}
public override void OnCreate(object hook)
{
m_mapControl = (IMapControl3)hook;
}
} }
放大至整个图层类ZoomToLayer:
using ESRI.ArcGIS.ADF.BaseClasses; using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Controls;
namespace _sdnMap {
///
/// 放大至整个图层
///
public sealed class ZoomToLayer : BaseCommand
{
private IMapControl3 m_mapControl;
public ZoomToLayer()
{
base.m_caption = \
}
public override void OnClick()
{
ILayer layer = (ILayer)m_mapControl.CustomProperty;
m_mapControl.Extent = layer.AreaOfInterest;
}
public override void OnCreate(object hook)
{
m_mapControl = (IMapControl3)hook;
}
} }
以上三个工具或命令的实现代码比较简单,在此不过多的分析,请读者自行理解。
下面在Form1_Load函数中进行菜单项的添加,代码如下:
//添加自定义菜单项到TOCCOntrol的Map菜单中 //打开文档菜单
m_menuMap.AddItem(new OpenNewMapDocument(m_controlsSynchronizer), esriCommandStyles.esriCommandStyleIconAndText);
//添加数据菜单
m_menuMap.AddItem(new ControlsAddDataCommandClass(), -1,
-1, 1, 0, false,
false,
esriCommandStyles.esriCommandStyleIconAndText);
//打开全部图层菜单
m_menuMap.AddItem(new LayerVisibility(), 1, 2, false, esriCommandStyles.esriCommandStyleTextOnly);
//关闭全部图层菜单
m_menuMap.AddItem(new LayerVisibility(), 2, 3, false, esriCommandStyles.esriCommandStyleTextOnly);
//以二级菜单的形式添加内置的“选择”菜单
m_menuMap.AddSubMenu(\
//以二级菜单的形式添加内置的“地图浏览”菜单
m_menuMap.AddSubMenu(\
//添加自定义菜单项到TOCCOntrol的图层菜单中
m_menuLayer = new ToolbarMenuClass();
//添加“移除图层”菜单项
m_menuLayer.AddItem(new RemoveLayer(), -1, 0, false, esriCommandStyles.esriCommandStyleTextOnly);
//添加“放大到整个图层”菜单项
m_menuLayer.AddItem(new ZoomToLayer(), -1, 1, true, esriCommandStyles.esriCommandStyleTextOnly);
//设置菜单的Hook
m_menuLayer.SetHook(m_mapControl);
m_menuMap.SetHook(m_mapControl); 3、
弹出右键菜单
顾名思义,右键菜单是在鼠标右键按下的时候弹出,所以我们要添加TOCControl1控件的OnMouseDown事件,实现代码如下:
private void axTOCControl1_OnMouseDown(object sender, ITOCControlEvents_OnMouseDownEvent e) {
//如果不是右键按下直接返回
if (e.button != 2) return;
esriTOCControlItem item = esriTOCControlItem.esriTOCControlItemNone;
IBasicMap map = null;
ILayer layer = null;
object other = null;
object index = null;
//判断所选菜单的类型
m_tocControl.HitTest(e.x, e.y, ref item, ref map, ref layer, ref other, ref index);
//确定选定的菜单类型,Map或是图层菜单
if (item == esriTOCControlItem.esriTOCControlItemMap)
m_tocControl.SelectItem(map, null);
else
m_tocControl.SelectItem(layer, null);
//设置CustomProperty为layer (用于自定义的Layer命令)
m_mapControl.CustomProperty = layer;
//弹出右键菜单
if (item == esriTOCControlItem.esriTOCControlItemMap)
m_menuMap.PopupMenu(e.x, e.y, m_tocControl.hWnd);
if (item == esriTOCControlItem.esriTOCControlItemLayer)
m_menuLayer.PopupMenu(e.x, e.y, m_tocControl.hWnd); }
同样的方法,我们也可以实现主地图控件的右键菜单,以方便地图浏览。添加MapControl1控件的OnMouseDown事件,实现代码如下:
///
/// 主地图控件的右键响应函数
///
///
///
private void axMapControl1_OnMouseDown(object sender, IMapControlEvents2_OnMouseDownEvent e) {
if (e.button == 2)
{
//弹出右键菜单
m_menuMap.PopupMenu(e.x,e.y,m_mapControl.hWnd);
} }
4、编译运行
按F5编译运行程序,你会发现,原来右键菜单实现起来是这么的简单啊!
下一讲中,我将给大家带的是TOCControl控件中图层拖拽(Drag and Drop)的实现。
ArcGIS Engine+C#实例开发教程》教程Bug及优化方案1
到第六讲为止已经发现的教程Bug及解决方法如下: 1、在第二讲可能会出现变量未定义。
原因:第二讲与第三讲联系紧密,我为控制篇幅才将其分为两讲,某些变量是在第三讲才进行定义,请大家注意。 2、第六讲弹不出TOCControl的右键菜单
原因:没有取得m_tocControl的指针,即没有把m_tocControl指针与axTOCControl1控件绑定,导致调用m_menuMap.PopupMenu(e.x, e.y, m_tocControl.hWnd);时m_tocControl.hWnd为NULL,故无法弹出菜单。 解决方法:在Form1_Load()函数中,添加如下代码: m_tocControl = (ITOCControl2)this.axTOCControl1.Object; 目前已经发现的优化方案如下:
1、教程第四讲,坐标单位前面的esri,原用switch语句逐一替换,其实直接用取子串(Substring)的方法截去更方便。 修改代码如下:
CoordinateLabel.Text = \当前坐标 X = \+ e.mapX.ToString() + \Y = \+ e.mapY.ToString() + \\+ this.axMapControl1.MapUnits.ToString().Substring(4);
2、教程第四讲,固定状态栏中的比例尺和当前坐标项目的宽度以防止闪烁。 方法如下:
选中状态栏中的比例尺或当前坐标项目,把其autoSize属性设为False,再在Size属性里设置宽度。经测试,比例尺宽度为150,当前坐标宽度为400比较合适。
《ArcGIS Engine+C#实例开发教程》第七讲 图层符号选择器的实现1
在上一讲中,我们实现了右键菜单(ContextMenu)的添加与实现,在最后我预留给下一讲的问题是TOCControl控件图层拖拽的实现。后来发现此功能的实现异常简单,只要在TOCControl的属性页中,勾选“Enable Layer Drag and Drop”即可。
这一讲,我们要实现的是图层符号选择器,与ArcMap中的Symbol Selector的类似。本讲较前几讲而言,些许有些复杂,不过只要仔细琢磨,认真操作,你就很容易实现如下所示的符号选择器。因为本讲篇幅较长,故我将其分成两个阶段,本文是第一阶段。
图1
在AE开发中,符号选择器有两种实现方式。
一是在程序中直接调用ArcMap中的符号选择器,如下所示:
图2
二是自定义符号选择器,如图1所示。
由于第一种方式前提是必须安装ArcGIS Desktop,其界面还是英文的,而对二次开发来说,大部分用户希望应该是中文界面。因此开发人员通常选择第二种方式,本讲也着重讲解第二种方式。
通过对《ArcGIS Engine+C#实例开发教程》前六讲的学习,我已经假定你已经基本熟悉C#语言和VS2005的操作,故在下面的教程中,我不准备说明每一步骤的具体操作方法,而只是说明操作步骤,以节省时间和篇幅。 1. 直接调用ArcMap中的符号选择器
(1)添加ESRI.ArcGIS.DisplayUI的引用。
分别在解决方案管理器和代码中添加引用。
(2)添加TOCControl的Double_Click事件。
(3)实现TOCControl的Double_Click事件。
因为种方法不是本讲的重点,故不对代码进行分析,有兴趣的读者请自行理解或结合后面的内容理解。代码如下: private void axTOCControl1_OnDoubleClick(object sender, ITOCControlEvents_OnDoubleClickEvent e) {
esriTOCControlItem toccItem = esriTOCControlItem.esriTOCControlItemNone; ILayer iLayer = null;
IBasicMap iBasicMap = null; object unk = null;
object data = null; if (e.button == 1) {
axTOCControl1.HitTest(e.x, e.y, ref toccItem, ref iBasicMap, ref iLayer, ref unk, ref data);
System.Drawing.Point pos = new System.Drawing.Point(e.x, e.y); if (toccItem == esriTOCControlItem.esriTOCControlItemLegendClass) {
ESRI.ArcGIS.Carto.ILegendClass pLC = new LegendClassClass(); ESRI.ArcGIS.Carto.ILegendGroup pLG = new LegendGroupClass(); if (unk is ILegendGroup) {
pLG = (ILegendGroup)unk; }
pLC = pLG.get_Class((int)data); ISymbol pSym;
pSym = pLC.Symbol;
ESRI.ArcGIS.DisplayUI.ISymbolSelector pSS = new ESRI.ArcGIS.DisplayUI.SymbolSelectorClass(); bool bOK = false;
pSS.AddSymbol(pSym); bOK = pSS.SelectSymbol(0); if (bOK) {
pLC.Symbol = pSS.GetSymbolAt(0); }
this.axMapControl1.ActiveView.Refresh();
this.axTOCControl1.Refresh();
} } }
(4)编译运行即可。
2. 自定义符号选择器
AE9.2提供了SymbologyControl控件,极大的方便了图层符号选择器的制作。本讲实现的符号选择器有如下功能。
用户双击TOCControl控件中图层的符号时,弹出选择符号对话框,对话框能够根据图层类型自动加载相应的符号,如点、线、面。用户可以调整符号的颜色、线宽、角度等参数。还可以打开自定义的符号文件(*.ServerStyle),加载更多的符号。
2.1 新建符号选择器窗体
新建Winodws窗体,命名为SymbolSelectorFrm,修改窗体的Text属性为“选择符号”。并添加SymboloryControl、PictureBox、Button、Label、NumericUpDown、GroupBox、ColorDialog、OpenFileDialog、ContextMenuStrip控件。控件布局如下所示:
图3
2.2 设置控件属性
设置相应控件的相关属性,如下表所示(空则不用修改): 控件 SymbologyControl PictureBox Label Label Label Label Label NumericUpDown NumericUpDown NumericUpDown Button Button Button Button Button GroupBox GroupBox ColorDialog OpenFileDialog ContextMenuStrip Name属性 axSymbologyControl ptbPreview lblColor lblSize lblWidth lblAngle lblOutlineColor nudSize nudWidth nudAngle btnColor btnOutlineColor btnMoreSymbols btnOK btnCancel groupBox1 groupBox2 colorDialog openFileDialog Text属性 颜色 大小 线宽 角度 外框颜色 (设置为空) (设置为空) 更多符号 确定 取消 预览 设置 其它 DialogResult属性设为OK Filter属性设置为:Styles 文件|*.ServerStyle contextMenuStripMoreSymbol 2.3 添加引用
在解决方案资源管理器中添加ArcGIS Engine的ESRI.ArcGIS.Geodatabase引用,在SymbolSelectorFrm.cs文件中添加
如下引用代码:
using ESRI.ArcGIS.Carto; using ESRI.ArcGIS.Display;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.SystemUI;
using ESRI.ArcGIS.Controls;
using ESRI.ArcGIS.Geodatabase;
2.4 初始化
(1) 添加SymbolSelectorFrm的全局变量,代码如下:
private IStyleGalleryItem pStyleGalleryItem;
private ILegendClass pLegendClass;
private ILayer pLayer;
public ISymbol pSymbol;
public Image pSymbolImage;
(2) 修改SymbolSelectorFrm的构造函数,传入图层和图例接口。代码如下:
///
/// 构造函数,初始化全局变量
///
///
///
public SymbolSelectorFrm(ILegendClass tempLegendClass, ILayer tempLayer) {
InitializeComponent();
this.pLegendClass = tempLegendClass;
this.pLayer = tempLayer; }
(3) 添加SymbolControl的SymbologyStyleClass设置函数SetFeatureClassStyle(),代码如下:
///
/// 初始化SymbologyControl的StyleClass,图层如果已有符号,则把符号添加到SymbologyControl中的第一个符号,并选中
///
///
private void SetFeatureClassStyle(esriSymbologyStyleClass symbologyStyleClass) {
this.axSymbologyControl.StyleClass = symbologyStyleClass;
ISymbologyStyleClass pSymbologyStyleClass = this.axSymbologyControl.GetStyleClass(symbologyStyleClass);
if (this.pLegendClass != null)
{
IStyleGalleryItem currentStyleGalleryItem = new ServerStyleGalleryItem();
currentStyleGalleryItem.Name = \当前符号\
currentStyleGalleryItem.Item = pLegendClass.Symbol;
pSymbologyStyleClass.AddItem(currentStyleGalleryItem,0);
this.pStyleGalleryItem = currentStyleGalleryItem;
}
pSymbologyStyleClass.SelectItem(0); }
(4) 添加注册表读取函数ReadRegistry(),此函数从注册表中读取ArcGIS的安装路径,代码如下:
///
/// 从注册表中取得指定软件的路径
///
///
///
private string ReadRegistry(string sKey) {
//Open the subkey for reading
Microsoft.Win32.RegistryKey rk = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(sKey, true);
if (rk == null) return \
// Get the data from a specified item in the key.
return (string)rk.GetValue(\ }
(5) 添加SymbolSelectorFrm的Load事件。根据图层类型为SymbologyControl导入相应的符号样式文件,如点、线、面,并设置控件的可视性。代码如下:
private void SymbolSelectorFrm_Load(object sender, EventArgs e) {
//取得ArcGIS安装路径
string sInstall = ReadRegistry(\
//载入ESRI.ServerStyle文件到SymbologyControl
this.axSymbologyControl.LoadStyleFile(sInstall + \
//确定图层的类型(点线面),设置好SymbologyControl的StyleClass,设置好各控件的可见性(visible)
IGeoFeatureLayer pGeoFeatureLayer = (IGeoFeatureLayer)pLayer;
switch (((IFeatureLayer)pLayer).FeatureClass.ShapeType) {
case ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPoint:
this.SetFeatureClassStyle(esriSymbologyStyleClass.esriStyleClassMarkerSymbols);
this.lblAngle.Visible = true;
this.nudAngle.Visible = true;
this.lblSize.Visible = true;
this.nudSize.Visible = true;
this.lblWidth.Visible = false;
this.nudWidth.Visible = false;
this.lblOutlineColor.Visible = false;
this.btnOutlineColor.Visible = false;
break;
case ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPolyline:
this.SetFeatureClassStyle(esriSymbologyStyleClass.esriStyleClassLineSymbols);
this.lblAngle.Visible = false;
this.nudAngle.Visible = false;
this.lblSize.Visible = false;
this.nudSize.Visible = false;
this.lblWidth.Visible = true;
this.nudWidth.Visible = true;
this.lblOutlineColor.Visible = false;
正在阅读:
ArcGIS Engine02-29
浅谈现代移动通信技术研究12-10
行政执法案件检查自查报告04-20
2015年最新SCI英文期刊影响因子04-11
实业公司薪酬体系设计方案04-14
江苏省高级人民法院《工伤认定行政案件审理指南》201006-04
鄂教版六年级语文下册全册教案 - 图文03-11
《进京城》观后感12-11
51单片机奇偶校验C51程序04-03
境外证件登记管理10-13
- 多层物业服务方案
- (审判实务)习惯法与少数民族地区民间纠纷解决问题(孙 潋)
- 人教版新课标六年级下册语文全册教案
- 词语打卡
- photoshop实习报告
- 钢结构设计原理综合测试2
- 2014年期末练习题
- 高中数学中的逆向思维解题方法探讨
- 名师原创 全国通用2014-2015学年高二寒假作业 政治(一)Word版
- 北航《建筑结构检测鉴定与加固》在线作业三
- XX县卫生监督所工程建设项目可行性研究报告
- 小学四年级观察作文经典评语
- 浅谈110KV变电站电气一次设计-程泉焱(1)
- 安全员考试题库
- 国家电网公司变电运维管理规定(试行)
- 义务教育课程标准稿征求意见提纲
- 教学秘书面试技巧
- 钢结构工程施工组织设计
- 水利工程概论论文
- 09届九年级数学第四次模拟试卷
- ArcGIS
- Engine
- 三年级数学期末试卷2014.1
- 自测题(一)电力系统的基本知识
- 中式烹调师初级理论试卷
- 心理诊断学平时作业答案集
- 小升初应用题综合训练22及参考答案2013
- 保险业务实验报告
- 蓝牙打印机操作规范
- 污水处理工培训讲义
- 新型气化炉耐火材料有关问题的探讨
- 论幼儿体育游戏的设计
- 审计案例分析及答案
- 推荐下载 护士演讲稿优秀范文 护士节优秀护士演讲稿范文-最新
- 2018北京市房屋租赁合同(自行成交版)
- 2020二年级语文上册课文24《曹冲称象》教案1新人教版
- 时代光华-如何组建高效合作的团队,100分
- 人教版小学语文五年级下册第三单元练习题
- 2018-2019-六年级小学生操行评语精选-优秀word范文(2页)
- 人大金融 - 2015年人大金融硕士考研经验箴言 - 图文
- Nace 2
- 《笔算乘法》说课稿上交版