目录
TODO:属性表”属性修改“,属性表”字段计算器“,”非创建要素过程中”的撤销重做。
4.1 纲要
4.1.1 思维导图
4.1.2 接口、枚举
- IEngineEditor,IEngineEditSketch,IEngineSketchOperation
- IPoint,IPointCollection,IGeometry,IGeometryCollection
4.1.3 效果动态图
4.2 编辑命令
撤销重做包括“创建要素”过程中和非“创建要素”过程中,难度较大。
4.2.1 开始编辑
//1 获取目标图层
cboEditingLyr.Items.Clear();
List<string> targetEditingLyr = BasicClass.GetFeatureLayerNameList(axMapControl.Map);
cboEditingLyr.Items.AddRange(targetEditingLyr.ToArray());
cboEditingLyr.SelectedIndex = 0;
//2 获取工作空间&开始编辑
IDataset pSet = (IDataset)m_pFeaLyr.FeatureClass;
IWorkspace pWs = pSet.Workspace;
m_pEditor.EnableUndoRedo(true);//开启撤销重做
m_pEditor.StartEditing(pWs, axMapControl.Map);
4.2.2 保存编辑
DialogResult isSave = MessageBox.Show("是否保存编辑?", "提示",
MessageBoxButtons.YesNo, MessageBoxIcon.Question);
IWorkspace pWs = m_pEditor.EditWorkspace;
if (isSave == DialogResult.Yes)
{
m_pEditor.StopEditing(true);
m_pEditor.StartEditing(pWs, axMapControl.Map);
axMapControl.Refresh();
}
4.2.3 停止编辑
DialogResult isSave = MessageBox.Show("是否保存编辑?", "提示",
MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (isSave == DialogResult.Yes)
m_pEditor.StopEditing(true);
else
m_pEditor.StopEditing(false);
4.2.4 撤销重做(创建要素过程中)
找了草图工具创建要素过程中撤销重做的官方接口很久,尝试了IEngineEditSketch,IEngineSketchOperation,IOperationStack接口发现效果并不是我想要的,最后只能确定官方不提供,只能用C#的堆栈类实现。
注:建议先看”创建要素“思路代码。
撤销
1. 初检:草图工具Geometry属性不为空;
2. 入栈:草图工具最后一个点;备份点栈;
3. 转为点串;
4. 删除最后一个点(面要素是倒数第二个点);
5. 复检:草图工具Geometry属性为空→关闭撤销许可。
//1 初检
if (!m_pSketch.Geometry.IsEmpty)
{
//2 入栈
m_pPntStack.Push(m_pSketch.LastPoint);
m_pPntStackCopy = m_pPntStack;//备份
//3 删除
IPointCollection pPntCol = (IPointCollection)m_pSketch.Geometry;
if (m_pSketch.GeometryType == esriGeometryType.esriGeometryPolygon
&& pPntCol.PointCount > 1)
pPntCol.RemovePoints(pPntCol.PointCount - 2, 1);
else
pPntCol.RemovePoints(pPntCol.PointCount - 1, 1);
m_pSketch.Geometry = (IGeometry)pPntCol;
//4 复检/更新许可
if (m_pSketch.Geometry.IsEmpty)
canUndo = false;
canRedo = true;
}
//5 刷新
m_pHookHelper.ActiveView.Refresh();
重做
1. 初检:栈内要素不为空;
2. 出栈:获取一个点;
3. 加点:草图工具添加一个点;
4. 复检:点栈为空→从备份栈获取,关闭重做许可。
//1 初检
if (m_pPntStack.Count > 0)
{
//2 出栈
IPoint pPnt = m_pPntStack.Pop();
//3 复检
if (m_pPntStack.Count == 0)
{
m_pPntStack = m_pPntStackCopy;
canRedo = false;
}
//4 添加
m_pSketch.AddPoint(pPnt, true);
//5 许可
canUndo = true;
}
//6 刷新
m_pHookHelper.ActiveView.Refresh();
快捷键设置
给axMapControl.ContextMenu属性赋值一个右键菜单。
4.3 要素编辑
4.3.1 创建要素
新建CreateFeatureTool类,实现ICommand和ITool接口,关键代码在ITool成员的OnMouseDown的响应事件中实现
public void OnMouseDown(int button, int shift, int x, int y)
{
//转成地图坐标
IPoint point = m_pHookHelper.ActiveView.ScreenDisplay.DisplayTransformation.ToMapPoint(x, y);
if (button == 1)
{
m_pSketch.AddPoint(point, true);//添加点
m_pPntStack.Clear();//清空栈
m_pPntStackCopy.Clear();//清空备份栈
canUndo = true;//允许撤销
isFinishedSketch = false;//创建要素过程中
}
}
//完成草图
public void OnDblClick()
{
m_pSketch.FinishSketch();
isFinishedSketch = true;
}
4.3.2 移动要素
使用组件库ICommand cmd = new ControlsEditingEditToolClass();
4.3.3 删除要素
使用组件库ICommand cmd = new ControlsEditingEditToolClass();
4.4 结点编辑
要理解”IHitTest.HitTest“参数
bool isTrue = hitShape.HitTest(点击点, 搜索范围, 搜索类型, 反馈点, ref 反馈距离,
ref hitPartIndex, ref hitSegmentIndex, ref bRightSide);
4.4.1 结点插入
参考帮助文档”CustomVertexCommands“,”EditingVertexCommands“。
public void OnMouseDown(int button, int shift, int x, int y)
{
//转成地图坐标
IPoint clickedPt = m_pHookHelper.ActiveView.ScreenDisplay.DisplayTransformation.ToMapPoint(x, y);
if (button == 1)
{
#region 1 获取点击测试参数
IHitTest hitShape = (IHitTest)m_pSketch.Geometry;
IPoint hitPoint = new PointClass();
double hitDistance = 0;
int hitPartIndex = 0;
int hitSegmentIndex = 0;
bool bRightSide = false;
esriGeometryHitPartType hitPartType = esriGeometryHitPartType.esriGeometryPartNone;
double searchRadius = 50;
#endregion
//2 节点判断
hitPartType = esriGeometryHitPartType.esriGeometryPartVertex;
bool isTrue = hitShape.HitTest(clickedPt, searchRadius, hitPartType, hitPoint, ref hitDistance,
ref hitPartIndex, ref hitSegmentIndex, ref bRightSide);
if (isTrue) return; //已存在节点,不需要添加
//3 点击测试
hitPartType = esriGeometryHitPartType.esriGeometryPartBoundary;
isTrue = hitShape.HitTest(clickedPt, searchRadius, hitPartType, hitPoint, ref hitDistance,
ref hitPartIndex, ref hitSegmentIndex, ref bRightSide);
//4 添加节点
if (isTrue)
{
//4.1 草图操作开始
IEngineSketchOperation pSketchOp = new EngineSketchOperationClass();
pSketchOp.Start(m_pEditor);
pSketchOp.SetMenuString("Insert Vertex (Custom)");
//4.2 获取点串
IGeometryCollection pGeoCol = (IGeometryCollection)m_pSketch.Geometry;
IPointCollection pPathOrRingPtCol = (IPointCollection)pGeoCol.get_Geometry(hitPartIndex);
//4.3 插入节点
object missing = Type.Missing;
object hitSegmentIndexObject = hitSegmentIndex;
object partIndexObject = hitPartIndex;
pPathOrRingPtCol.AddPoint(hitPoint, ref missing, ref hitSegmentIndexObject);
//4.4 移除旧的,添加新的
pGeoCol.RemoveGeometries(hitPartIndex, 1);
pGeoCol.AddGeometry((IGeometry)pPathOrRingPtCol, ref partIndexObject, ref missing);
//4.5 草图操作完成
esriEngineSketchOperationType opType =
esriEngineSketchOperationType.esriEngineSketchOperationVertexAdded;
pSketchOp.Finish(null, opType, hitPoint);
}
}
}
4.4.2 结点删除
public void OnMouseDown(int button, int shift, int x, int y)
{
//转成地图坐标
IPoint clickedPt = m_pHookHelper.ActiveView.ScreenDisplay.DisplayTransformation.ToMapPoint(x, y);
if (button == 1)
{
#region 1 获取点击测试参数
IHitTest hitShape = (IHitTest)m_pSketch.Geometry;
IPoint hitPoint = new PointClass();
double hitDistance = 0;
int hitPartIndex = 0;
int hitSegmentIndex = 0;
bool bRightSide = false;
esriGeometryHitPartType hitPartType = esriGeometryHitPartType.esriGeometryPartNone;
double searchRadius = 50;
#endregion
//2 节点判断
hitPartType = esriGeometryHitPartType.esriGeometryPartVertex;
bool isTrue = hitShape.HitTest(clickedPt, searchRadius, hitPartType, hitPoint, ref hitDistance,
ref hitPartIndex, ref hitSegmentIndex, ref bRightSide);
//3 删除节点
if (isTrue)
{
//3.1 草图操作开始
IEngineSketchOperation pSketchOp = new EngineSketchOperationClass();
pSketchOp.Start(m_pEditor);
pSketchOp.SetMenuString("Delete Vertex (Custom)");
//3.2 获取点串
IGeometryCollection pGeoCol = (IGeometryCollection)m_pSketch.Geometry;
IPointCollection pPathOrRingPtCol = (IPointCollection)pGeoCol.get_Geometry(hitPartIndex);
//3.3 删除节点
object missing = Type.Missing;
object partIndexObject = hitPartIndex;
pPathOrRingPtCol.RemovePoints(hitSegmentIndex, 1);
//4.4 移除旧的,添加新的
pGeoCol.RemoveGeometries(hitPartIndex, 1);
pGeoCol.AddGeometry((IGeometry)pPathOrRingPtCol, ref partIndexObject, ref missing);
//4.5 草图操作完成
esriEngineSketchOperationType opType =
esriEngineSketchOperationType.esriEngineSketchOperationVertexDeleted;
pSketchOp.Finish(null, opType, hitPoint);
}
}
}
4.4.3 结点移动
使用组件库ICommand cmd = new ControlsEditingEditToolClass();
4.5 属性编辑
注:这里的保存是保存在”工作空间“,还没有保存到数据库中,需要点击【保存编辑】才是真正的保存在数据库中
4.5.1 对话框布局
4.5.1 关键代码
for (int i = 0; i < dgvAttributeEdit.RowCount; i++)
{
string sFieldName = (string)dgvAttributeEdit.Rows[i].Cells[0].Value;
object objFieldValue = dgvAttributeEdit.Rows[i].Cells[1].Value;
if (sFieldName != null && sFieldName != string.Empty
&& !sFieldName.ToUpper().Equals("OBJECTID") && objFieldValue != null)
{
int index = m_pFea.Fields.FindField(sFieldName);
m_pFea.Value[index] = objFieldValue;
}
}
m_pFea.Store();