这是前辈学姐写的代码,如果没有学姐的教程我根本不会做。ArcEngine C# GIS开发入门作业 (二)Ex03——基本应用程序生成,右击菜单实现:显示、移除和打开属性表功能_arcengine c#作业-CSDN博客这是前辈学姐写的教程,如果没有学姐的教程我根本不会做。这是前辈学姐写的代码,如果没有学姐的教程我根本不会做。ArcEngine C# GIS开发入门作业 (二)Ex03——基本应用程序生成,右击菜单实现:显示、移除和打开属性表功能_arcengine c#作业-CSDN博客
另外学姐里面的两个链接也很有帮助。
ArcGIS Engine入门教程_第六章_实现右键菜单 - GIS知乎-新一代GIS问答社区 (geoscene.cn)
ArcGIS Engine入门教程_第四章_创建Engine应用程序 - GIS知乎-新一代GIS问答社区 (geoscene.cn)
一、作业要求
- 在状态栏显示Map中鼠标当前位置的坐标信息(MapControl的OnMouseMove)。
- 在状态栏显示工具条命令的提示信息(ToolbarControl的OnMouseMove、HitTest)。
- 在TOCControl的图层上按鼠标右键,移除该图层(TOCControl的OnMouseDown、HitTest)
二、作业过程
1.新建MapControl Application
这是一个基本的ArcGIS应用的模板,里面有基础的代码,当然也可以自己从空白的Windows窗体应用自己搭建。看过上一个作业的UU应该会自己搭建了。
2.窗体布局
关于工具箱里的控件上一个作业已经有详细的介绍,再加上是直接使用的模板,这一个作业就不再一一赘述,可以参照下方截图自行拖拽控件。
应当注意的上图是X坐标,Y坐标,工具名称等内容是在属性表的Text内改的,而代码对应的是在(Name)内更改。
3.引用的类库
补充一下以下类似问题的解决方法
Shift选中所有的引用的类库,把属性表的嵌入互操作类型改为False。
4.编写代码
a.MainForm.cs
引入的命名空间
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.IO;
using System.Runtime.InteropServices;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Controls;
using ESRI.ArcGIS.ADF;
using ESRI.ArcGIS.SystemUI;
代码
namespace EX02
{
public sealed partial class MainForm : Form
{
#region class private members
private IMapControl3 m_mapControl = null;
private string m_mapDocumentName = string.Empty;
#endregion
#region class constructor
public MainForm()
{
InitializeComponent();
}
#endregion
private void MainForm_Load(object sender, EventArgs e) //加载窗口
{
//get the MapControl
m_mapControl = (IMapControl3)axMapControl1.Object;
//disable the Save menu (since there is no document yet)
menuSaveDoc.Enabled = false;
}
#region Main Menu event handlers (MapControl Application默认代码)
private void menuNewDoc_Click(object sender, EventArgs e)
{
//execute New Document command
ICommand command = new CreateNewDocument();
command.OnCreate(m_mapControl.Object);
command.OnClick();
}
private void menuOpenDoc_Click(object sender, EventArgs e)
{
//execute Open Document command
ICommand command = new ControlsOpenDocCommandClass();
command.OnCreate(m_mapControl.Object);
command.OnClick();
}
private void menuSaveDoc_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;
}
//Replace its contents with the current map
mapDoc.ReplaceContents((IMxdContents)m_mapControl.Map);
//save the MapDocument in order to persist it
mapDoc.Save(mapDoc.UsesRelativePaths, false);
//close the MapDocument
mapDoc.Close();
}
}
private void menuSaveAs_Click(object sender, EventArgs e)
{
//execute SaveAs Document command
ICommand command = new ControlsSaveAsDocCommandClass();
command.OnCreate(m_mapControl.Object);
command.OnClick();
}
private void menuExitApp_Click(object sender, EventArgs e)
{
//exit the application
Application.Exit();
}
#endregion
private void axMapControl1_OnMapReplaced(object sender, IMapControlEvents2_OnMapReplacedEvent e)
{
//因为与作业要求冲突,我把代码删除了
}
#region 1.鼠标移动在地图上时,显示坐标
private void axMapControl1_OnMouseMove(object sender, IMapControlEvents2_OnMouseMoveEvent e)//定义一个私有方法 axMapControl1_OnMouseMove,该方法在鼠标在地图控件axMapControl1上移动时被触发。
{
XtoolStripStatusLabel.Text = "X:" + e.mapX.ToString("0.00");// 更新名为XtoolStripStatusLabel的文本标签的文本内容,显示鼠标当前在地图上的X坐标。
YtoolStripStatusLabel.Text = "Y:" + e.mapY.ToString("0.00")+"米";// 更新名为YtoolStripStatusLabel的文本标签的文本内容,显示鼠标当前在地图上的Y坐标。
int index = axToolbarControl1.HitTest(e.x, e.y, false); 使用axToolbarControl1的HitTest方法,获取鼠标当前位置(由e.x和e.y给出)的工具的索引号。第三个参数false表示不进行反色显示。
if (index != -1) // 如果返回的索引不是-1,表示鼠标在工具栏上的某个工具上。
{
toolStripStatusLabel.Text = axToolbarControl1.GetItem(index).Command.Message; // 获取该工具的命令,并获取该命令的消息文本,然后设置为toolStripStatusLabel3的文本。
}
else // 如果返回的索引是-1,表示鼠标没有在工具栏的任何工具上。此时将toolStripStatusLabel3的文本设置为"就绪"。
{
toolStripStatusLabel.Text = "就绪"; // 获取该工具的命令,并获取该命令的消息文本,然后设置为toolStripStatusLabel3的文本。
}
}
#endregion
private void axToolbarControl1_OnMouseDown(object sender, IToolbarControlEvents_OnMouseDownEvent e)//用于处理在工具栏控件(axToolbarControl1)上移动鼠标时的事件。
{
}
private void axLicenseControl1_Enter(object sender, EventArgs e)
{
//若不通过点击LicenseControl添加,则无法正常运行
}
private void axMapControl1_OnMouseDown(object sender, IMapControlEvents2_OnMouseDownEvent e)
{
}
#region 3.右击菜单图层的实现,以下代码块是为了实现点击位置与contextMenuStrips1的联系。
//右键[设计页面]最下方的contextMenuStrips1在弹出来的里面填写内容,出来的即是右键单击图层出来的
public ILayer pLayer; //全局变量 pLayer 被设置为 FeatureLayerClass 的一个实例。全局变量的主要目的是在整个程序中都可以访问和使用。被用于在整个程序中共享地图图层的引用,使得在不同的函数和方法中都可以操作该图层。
private void axTOCControl1_OnMouseDown(object sender, ITOCControlEvents_OnMouseDownEvent e)//object sender: 这表示这个事件处理程序是由哪个对象触发的。在鼠标事件中,sender通常是触发事件的控件本身。
//ITOCControlEvents_OnMouseDownEvent e: 这是一个接口事件参数,它包含了关于鼠标点击事件的信息,例如鼠标的位置、按键信息等。
{
if (axMapControl1.LayerCount > 0)
{
esriTOCControlItem pItem = new esriTOCControlItem();
//pGlobeLayer为全局变量
pLayer = new FeatureLayerClass();
IBasicMap pBasicMap = new MapClass();
object pOther = new object();
object pIndex = new object();
//获取点击的位置
axTOCControl1.HitTest(e.x, e.y, ref pItem, ref pBasicMap, ref pLayer, ref pOther, ref pIndex);
//点击的是Layer的话,则弹出上下文菜单
if (e.button == 2 && pItem == esriTOCControlItem.esriTOCControlItemLayer)
{
contextMenuStrip1.Show(axTOCControl1, e.x, e.y);
}
}
}
#endregion
#region 4.图层移除功能实现 双击【设计】窗口的contextMenuStrip对应的移除图层
//这段代码的意思是:如果MapControl中有至少一个图层,并且pLayer不为空,那么删除pLayer图层。
private void 移除图层ToolStripMenuItem_Click(object sender, EventArgs e)
{
if (axMapControl1.LayerCount > 0) //这个条件检查MapControl(axMapControl1)中的图层数量是否大于0。如果图层数量大于0,那么执行花括号中的代码。
{
if (pLayer != null) //这个条件检查变量pLayer是否不为空。如果pLayer不为空,那么执行花括号中的代码。
{
axMapControl1.Map.DeleteLayer(pLayer);//如果上述两个条件都满足,那么删除指定的图层pLayer。
}
}
}
#endregion
#region 5.属性表功能实现,需要在这个项目里新建一个窗体。同样是双击【设计】窗口的contextMenuStrip对应的打开属性表
//属性表窗体连接并显示。通常用于响应菜单项点击等用户操作。这段代码的功能是打开一个属性表窗体并显示它。
private void 打开属性表ToolStripMenuItem_Click_1(object sender, EventArgs e)//这是事件处理函数的定义。它表示当名为"openAtriiToolStripMenuItem"的菜单项被点击时,执行这个函数。
{
AttributeTable pAttributeTable = new AttributeTable(pLayer as IFeatureLayer);//这行代码创建了一个新的AttributeTable对象。这个对象通常用于显示地理数据(具体取决于你使用的GIS库)。
//是将pLayer强制转换为IFeatureLayer类型。IFeatureLayer通常表示一个包含特征的图层。
//遇到了困难AttributeTable不包含采用1个参数的构造函数好像是通过双击解决的
//不太明白两个窗体是怎么关联的,似乎又明白,那种感觉是不会自己用
pAttributeTable.Show();//这行代码调用AttributeTable对象的Show方法,以打开并显示这个属性表窗体。
}
#endregion
}
}
属性表相关的操作不放了,只放代码,请参考文章开头链接,前辈写的很详细了。
b.AttributeTable.cs
引入的命名空间
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Geodatabase;
代码
namespace EX02
{
public partial class AttributeTable : Form
{
private IFeatureLayer pFeatureLayer = null;// 定义私有变量pFeatureLayer,它是IFeatureLayer类型的对象,主要用来存储要素图层的信息。
public AttributeTable(IFeatureLayer _FeatureLayer) //这里括号里的内容对应MainForm的“ AttributeTable不包含采用1个参数的构造函数”
{
InitializeComponent();
pFeatureLayer = _FeatureLayer;
}
private void AttributeTable_Load_1(object sender, EventArgs e)// 当属性表格被加载时,会触发此事件处理程序。
{
IFields pFields;// 定义一个IFields类型的变量pFields,此接口通常用于ArcGIS,代表特性类的一部分,连接属性表的列。
pFields = pFeatureLayer.FeatureClass.Fields;//连接属性表的列
dataGridView1.ColumnCount = pFields.FieldCount; // 设置DataGridView控件的列数与pFields中的字段数量相同。
for (int i = 0; i < pFields.FieldCount; i++) // 循环遍历pFields中的所有字段。
{
string fldName = pFields.get_Field(i).Name;// 获取当前字段的名称。
dataGridView1.Columns[i].Name = fldName; // 设置DataGridView控件中当前列的名称与获取到的字段名称相同。
dataGridView1.Columns[i].ValueType = Type.GetType(ParseFieldType(pFields.get_Field(i).Type)); // 通过ParseFieldType函数获取字段类型,并设置为此列的值类型。此部分可能需要特定方法来解析不同类型的字段。
}
IFeatureCursor pFeatureCursor; // 定义一个IFeatureCursor类型的变量pFeatureCursor,此接口通常用于ArcGIS,代表特性类的一部分,定义游标/指针。
pFeatureCursor = pFeatureLayer.FeatureClass.Search(null, false); // 通过pFeatureLayer的FeatureClass获取一个搜索游标并将它赋值给pFeatureCursor。
IFeature pFeature; // 定义一个IFeature类型的变量pFeature,此接口通常用于ArcGIS,代表特性类的一部分。
pFeature = pFeatureCursor.NextFeature(); // 通过搜索游标获取特性并将它赋值给pFeature。
while (pFeature != null) // 当特性不为空时,进入循环。
{
string[] fldValue = new string[pFields.FieldCount]; // 定义一个字符串数组fldValue,其长度与字段数量相同。此数组将用于存储从特性中获取的字段值。
for (int i = 0; i < pFields.FieldCount; i++)// 循环遍历所有字段。
{
// 定义一个字符串变量fldName,用于存储当前字段的名称。
string fldName;
fldName = pFields.get_Field(i).Name;
// 下面的代码判断字段名称是否与特性图层的形状字段名称相同。
if (fldName == pFeatureLayer.FeatureClass.ShapeFieldName)
{
// 如果相同,则获取特性的几何类型并将其转换为字符串形式,然后赋值给fldValue数组的相应位置。
fldValue[i] = pFeature.Shape.GeometryType.ToString().Remove(0, 12);
}
else
fldValue[i] = pFeature.get_Value(i).ToString(); // 如果不相同,则获取特性的当前字段的值并将其转换为字符串形式,然后赋值给fldValue数组的相应位置。
}
dataGridView1.Rows.Add(fldValue); // 将fldValue数组中的值添加到DataGridView控件的行中,以显示这些值。
pFeature = pFeatureCursor.NextFeature(); // 移动到下一个特性。
}
}
#region //不知道using ESRI.ArcGIS.Carto命名空间;和引用类库的区别
// "using ESRI.ArcGIS.Carto;" 和 "引用类库" 的区别在于前者是C#语言中的一种指令,而后者是一种编程行为。
//"using ESRI.ArcGIS.Carto;" 是一个using指令,它告诉编译器在代码中使用的ESRI.ArcGIS.Carto命名空间。这个命名空间是ArcGIS软件中用于地图和图层相关操作的一部分。使用这个指令的目的是为了让代码更简洁,避免在每次使用该命名空间中的类或方法时都需要写出完整的命名空间。
//"引用类库" 是一种编程行为,它是指将第三方库或自己编写的库添加到项目中,以便在代码中使用这些库中的类、接口或方法。通常需要通过添加引用或使用NuGet包管理器等方式来引用类库。引用类库的目的是为了扩展程序的功能,利用其他人或自己已经编写好的代码来快速实现特定功能,提高开发效率。
//总之,"using ESRI.ArcGIS.Carto;" 是C#语言中的一种指令,用于引用命名空间,而引用类库是一种编程行为,用于扩展程序的功能。
//下面这引用大概就是右侧引用里的东西,关于ArcGIS类库的引用,右键单击引用-添加引用-程序集-扩展勾选即可
#endregion
private string ParseFieldType(esriFieldType TableFieldType)//该程序需要处理ArcGIS特性表的字段类型,并需要将这些类型映射到.NET数据类型。
{
switch (TableFieldType)
{
// 如果TableFieldType的值是esriFieldType.esriFieldTypeBlob,返回"System.String"。
case esriFieldType.esriFieldTypeBlob:
return "System.String";
case esriFieldType.esriFieldTypeDate:
return "System.DateTime";
case esriFieldType.esriFieldTypeDouble:
return "System.Double";
case esriFieldType.esriFieldTypeGeometry:
return "System.String";
case esriFieldType.esriFieldTypeGlobalID:
return "System.String";
case esriFieldType.esriFieldTypeGUID:
return "System.String";
case esriFieldType.esriFieldTypeInteger:
return "System.Int32";
case esriFieldType.esriFieldTypeOID:
return "System.String";
case esriFieldType.esriFieldTypeRaster:
return "System.String";
case esriFieldType.esriFieldTypeSingle:
return "System.Single";
case esriFieldType.esriFieldTypeSmallInteger:
return "System.Int32";
case esriFieldType.esriFieldTypeString:
return "System.String";
default:
return "System.String";
}
}
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
}
}
}
c.Program.cs
引入的命名空间
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using ESRI.ArcGIS;
代码
namespace EX02
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
if (!RuntimeManager.Bind(ProductCode.Engine))
{
if (!RuntimeManager.Bind(ProductCode.Desktop))
{
MessageBox.Show("Unable to bind to ArcGIS runtime. Application will be shut down.");
return;
}
}
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
}
}
三、作业成果
- 在状态栏显示Map中鼠标当前位置的坐标信息(MapControl的OnMouseMove)。
- 在状态栏显示工具条命令的提示信息(ToolbarControl的OnMouseMove、HitTest)。
- 在TOCControl的图层上按鼠标右键,移除该图层(TOCControl的OnMouseDown、HitTest)