最近在做一个地理信息系统,需要实现缓冲区分析的功能。在网上、参考书上参考别人的代码。发现了一个大bug,一直解决不了,遂奋战至凌晨三点半。终于解决啦~
先搭建窗体:
选择图层 :comboBox1
缓冲距离 :textBox1
输出路径 :textBox2
确认:button1
取消:button2
(一)变量以及构造函数的的定义
//变量的定义
private IActiveView pActiveView;
private AxMapControl mapControl;
public Buffer()
{
InitializeComponent();
}
//构建含参构造函数,将主窗体的AxMapControl传进来
public Buffer(AxMapControl mainMapControl):this()
{
mapControl = mainMapControl;
pActiveView = mainMapControl.ActiveView;
}
//窗体加载
private void Buffer_Load(object sender, EventArgs e)
{
if (mapControl == null || pActiveView.FocusMap.LayerCount == 0)
{
return;
}
IEnumLayer layers = pActiveView.FocusMap.get_Layers();
layers.Reset();
ILayer layer = layers.Next();
while (layer != null)
{
comboBox1.Items.Add(layer.Name);
layer = layers.Next();
}
}
//设置输出路径
private void textBox2_MouseDown(object sender, MouseEventArgs e)
{
//set the output layer
SaveFileDialog saveDlg = new SaveFileDialog();
saveDlg.CheckPathExists = true;
saveDlg.Filter = "Shapefile (*.shp)|*.shp";
saveDlg.OverwritePrompt = true;
saveDlg.Title = "Output Layer";
saveDlg.RestoreDirectory = true;
saveDlg.FileName = (string)comboBox1.SelectedItem + "_buffer.shp";
DialogResult dr = saveDlg.ShowDialog();
if (dr == DialogResult.OK)
textBox2.Text = saveDlg.FileName;
}
//取消
private void button2_Click(object sender, EventArgs e)
{
this.Close();
}
//获取图层源路径
public static string getLayerPath(ILayer pLayer)
{
IDatasetName pDatasetName = (pLayer as IDataLayer2).DataSourceName as IDatasetName;
IWorkspaceName pWorkspaceName = pDatasetName.WorkspaceName;
return pWorkspaceName.PathName + "\\" + pLayer.Name + ".shp";
}
//确认
private void button1_Click(object sender, EventArgs e)
{
double bufferDistance = Convert.ToDouble(textBox1.Text.Trim());
if (bufferDistance == 0.0)
{
MessageBox.Show("缓冲区距离有误!");
return;
}
if (comboBox1.Text == string.Empty)
{
MessageBox.Show("输入图层不能为空!");
return;
}
if (textBox2.Text == string.Empty)
{
MessageBox.Show("输出路径不能为空!");
return;
}
int index = comboBox1.SelectedIndex;
string name = getLayerPath(pActiveView.FocusMap.get_Layer(index));
string outPath = textBox2.Text;
//Geoprocessor对象的定义
ESRI.ArcGIS.Geoprocessor.Geoprocessor pGp = new ESRI.ArcGIS.Geoprocessor.Geoprocessor();
//以下两种情况下会报错。
//GeoProcessor pGp = new GeoProcessor();
//IGeoProcessor2 pGp = new GeoProcessorClass();
pGp.OverwriteOutput = true; //允许运算结果覆盖现有文件,可无
ESRI.ArcGIS.AnalysisTools.Buffer pBuffer = new ESRI.ArcGIS.AnalysisTools.Buffer();
//获取缓冲区分析图层
ILayer pLayer = pActiveView.FocusMap.get_Layer(index);
IFeatureLayer featLayer = pLayer as IFeatureLayer;
//IFeatureCursor cursor = featLayer.Search(null, false);
//IFeature feaClass = cursor.NextFeature();
pBuffer.in_features = featLayer;
pBuffer.out_feature_class = outPath; //输出路径
pBuffer.buffer_distance_or_field = bufferDistance; //缓冲区参数
pBuffer.dissolve_option = "NONE"; //融合缓冲区重叠交叉部分,如果不融合填"ALL"
pGp.Execute(pBuffer, null); //执行
string pFolder = System.IO.Path.GetDirectoryName(outPath); //得到字符串中文件夹位置
string pFileName = System.IO.Path.GetFileName(outPath); //得到字符串中文件名字
mapControl.AddShapeFile(pFolder, pFileName); //往地图控件里添加文件
mapControl.ActiveView.Refresh(); //激活窗口刷新
this.Close();
}
对于我上面提到的bug,就是在我在执行GeoProcessor.Excute()方法时,一直弹出以下错误:
昨天遇到这个问题,当时差点崩溃,因为查了一天资料,别人的用法都是这样。差点想重装VS。突然灵机一动,去对象浏览器里看了一下:
解决方法:
定义Geoprocessor对象时,要用:
ESRI.ArcGIS.Geoprocessor.Geoprocessor pGp = new ESRI.ArcGIS.Geoprocessor.Geoprocessor();
而不能直接用:
GeoProcessor pGp = new GeoProcessor();
补充:
在写这篇博客时,我又想到:是不是我加的引用不对?我昨天其实已经加了GeoProcessor的引用,后来发现没用到,就注释掉了,但是我发现:将GeoProcessor改成小写p的Geoprocessor,就不用那么麻烦了。
using ESRI.ArcGIS.Geoprocessor;
Geoprocessor GP = new Geoprocessor();
emmmm…一定要细心!
2021/4/12 更新:评论很多人要主窗体代码,更新一下。
ps.这个项目太久远了,当时很多技术和意识都不太成熟,用了很多公共变量,暂时没时间完善了,(先活过毕设),大家凑活看吧。
//主窗体界面的公共变量
IExtractionOp extractOp = null;//提取分析对象
IGeoDataset maskRaster = null;//掩膜数据集
IGeoDataset inGeodataset = null;//输入数据集
IGeoDataset outGeodataset = null;//输出数据集
IFeatureLayer pTocFeatureLayer;//当前所选矢量图层
IEngineEditor pEngineEditor = new EngineEditorClass();//启动或停止编辑
IEngineEditTask pEngineEditTask = null;
IEngineEditLayers pEngineEditLayers = null;
IActiveView pActiveView = null;
IRasterLayer pOutRasLayer;//输出栅格
IRasterLayer pRasterLayer;//所选栅格
IRaster raster;
Color Color;
ILayer pLayer = null;//被选中的图层
private frmMapTips frmMapTips = null;//MapTips
string filepath = System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase;//获取应用程序的目录
private ISelectionEnvironment selectionEnvironment;//定义接口对象来设置选择环境
private IMap pMap = null;
private string sMxdPath = Application.StartupPath;
int flag = 0;//标志是否点击了“添加图名”
int ind;//当前所选图层的序号
接下来是主窗体界面的无参构造函数
public MainForm()
{
InitializeComponent();
InitObject();
//窗体初始化时新建接口对象,对象具有默认的选项设置值
selectionEnvironment = new SelectionEnvironmentClass();
}
private void InitObject()
{
try
{
//ChangeButtonState(false);
pEngineEditor = new EngineEditorClass();//实例化IEngineEditor接口类型的对象,表示启动或者停止编辑
OperateMap.EngineEditor = pEngineEditor;//将该对象的值传到MapManager类中的同接口类型的变量
pEngineEditTask = pEngineEditor as IEngineEditTask;//接口转换,将IEngineEditor接口转换为IEngineEditTask接口,设置编辑任务
pEngineEditLayers = pEngineEditor as IEngineEditLayers;//接口转换,将IEngineEditor接口转换为IEngineEditLayers接口,设置编辑图层
sMxdPath = OperateMap.getPath(sMxdPath) + "\\data\\edit.mxd"; ;//获取Mxd文件的路径
if (mainMapControl.CheckMxFile(sMxdPath))
{
mainMapControl.LoadMxFile(sMxdPath);
}
pMap = mainMapControl.Map;
pActiveView = mainMapControl.Map as IActiveView;//刷新视图
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
调用时的代码:
private void 缓冲区分析ToolStripMenuItem_Click(object sender, EventArgs e)
{
Buffer bf = new Buffer(mainMapControl);
bf.Show();
}
=====================2023/12/29更新=
这个项目太久远啦,而且我现在由于硕士转专业了,电脑也没有ArcGIS环境了。评论很多细节我回答不上来,把代码和运行视频放上来帮助大家学习。数据因为我们老师说不能外传,所以抱歉啦!
链接:https://pan.baidu.com/s/1xefFX4ruj5mI819illszhQ
提取码:dxe1