今天终于大概把树形的图层目录给解决了。前面一直卡壳卡在鼠标选择的矢量图层pTocFeatureLayer没有办法转换为IGroupLayer,一直都在提示pTocFeatureLayer为null。
但是无意间,也可能是逐渐理解了图层栏AxTOCControl和图层组的含义,网上没有现成的代码,于是我就自己摸索了一下。首先图层栏中的数据框Map是一个关键,这个可以通过axMapcontrol.Map获取Map对象,然后可以通过axMapcontrol.Map.AddLayer()方法来添加图层,于是可以实例化一个groupLayer对象:
IGroupLayer groupLayer = new GroupLayerClass();
然后通过axMapcontrol.Map.AddLayer(groupLayer)就在Map下面添加了一个图层组。有木有很简单,但是刚刚开始做的时候是一点头绪都没有。
紧接着,可以在groupLayer下面添加自己想要的图层:
groupLayer.Add(getLayer);
简单来说,要想在map中添加一个图层组,图层组中添加图层:
IGroupLayer groupLayer = new GroupLayerClass();
axMapcontrol.Map.AddLayer(groupLayer);
groupLayer.Add(Layer);
但是我在想啊,我是直接读取的shp文件然后加载显示啊,不能直接获取layera啊,这样的话图层栏里面会先加载出不是图层组的layer,但是这不在图层组下面啊,我想要的是把他搞到图层组下面去。就像下面
于是我又想啊,groupLayer对象有没有直接根据文件路径和文件名直接加载显示的方法呢。嘿嘿嘿,不好意思没有。于是就只能把通过读取文件显示的layer转移到图层组下面去。脑洞造起来~
我是这样解决的:首先直接通过文件路径和文件名加载图层,然后写了一个方法,遍历图层下面的layer,把想要显示的图层名传进去,如果在图层栏中找到了这个图层,就返回它。
private ILayer GetLayersByName(string IN_Name)
{
IEnumLayer Temp_AllLayer = axMapcontrol.Map.Layers;
ILayer Each_Layer = Temp_AllLayer.Next();
while (Each_Layer != null)
{
if (Each_Layer.Name.Contains(IN_Name))
return Each_Layer;
Each_Layer = Temp_AllLayer.Next();
}
return null;
}
于是乎,我拿到了layer,使用groupLayer.Add(getLayer);就可以显示了。但出现问题了:这样单独的,不是图层组那个layer还在啊,所以还要考虑把它删掉。
我又写了一个DeleteLyersByName()方法,传想删除的图层名进去,遍历Map下面的layer,但是如果碰到的layer不是图层组的话,并且它的名字和图层组下面的那个layer的名字相同就删去。
//根据图层名删除图层
private void DeleteLyersByName(string IN_Name)
{
ILayer pL = null;
for (int i = 0; i < axMapcontrol.LayerCount; i++)
{
pL = axMapcontrol.get_Layer(i);
if (pL as IGroupLayer==null)
{
if (pL.Name.Contains(IN_Name))
axMapcontrol.Map.DeleteLayer(pL);
}
}
}
于是乎,这样就只剩下图层组了。但是问题又来了:怎么执行之后,图层栏中的图层没变勒??点图层前的+号刷新一下,可以了。但是直接添加一句:axTOCControl.Update();图层栏就正常显示了。
问题源源不断:我重复添加一个文件的时候,它会在图层栏重复的添加显示。。。。于是我又写了一个方法,哎,真的人艰不拆。
isLoadSameLayer(string IN_Name)方法,把图层名传进去,又遍历一下Map下面的图层,
//遍历判断图层中是否已经加载了相应的图层
private bool isLoadSameLayer(string IN_Name)
{
ILayer pL = null;
string name = "";
if (axMapcontrol.LayerCount != 0)
{
for (int i = 0; i < axMapcontrol.LayerCount;i++ )
{
pL = axMapcontrol.get_Layer(i);//获取图层组和图层
if (pL is IGroupLayer)
{
ICompositeLayer pGroupLayer = pL as ICompositeLayer;
for (int j = 0; j < pGroupLayer.Count; j++)
{
name = pGroupLayer.get_Layer(j).Name;
if (IN_Name == name)
return true;
}
}
else//如果不是图层组
{
name = pL.Name;
if (IN_Name == name)
return true;
}
}
}
return false;//默认没有加载相同的图层
}
注意哦,使用pL = axMapcontrol.get_Layer(i)只会获取单独的图层和图层组,而不会获得图层组下面的图层。
使用ICompositeLayer pGroupLayer = pL as ICompositeLayer;获取图层组下面的图层,然后判断一下图层名和传进来的名字是不是一样的,一样的就不加载了,返回一个true,表明找到了。这样就不会重复加载了。
还有个问题(问题咋那么多呢),我删除图层得一个一个删啊,多费事啊,于是给map整个右键点击事件,添加一个移除所有图层的方法。具体如下
// TOCControl的OnMouseDown事件
private void axTOCControl1_OnMouseDown(object sender, ESRI.ArcGIS.Controls.ITOCControlEvents_OnMouseDownEvent e)
{
if (e.button == 2)//点击的是鼠标右键
{
esriTOCControlItem pItem = esriTOCControlItem.esriTOCControlItemNone;
IBasicMap pMap = null;
ILayer pLayer = null;
object unk = null;
object data = null;
axTOCControl1.HitTest(e.x, e.y, ref pItem, ref pMap, ref pLayer, ref unk, ref data);
pTocFeatureLayer = pLayer as IFeatureLayer;
if (pItem == esriTOCControlItem.esriTOCControlItemLayer && pTocFeatureLayer != null)
{
btnLayerSel.Enabled = !pTocFeatureLayer.Selectable;
btnLayerUnSel.Enabled = pTocFeatureLayer.Selectable;
contextMenuStrip1.Show(Control.MousePosition);
}
if (pItem == esriTOCControlItem.esriTOCControlItemMap)
{
//btnLayerSel.Enabled = !pTocFeatureLayer.Selectable;
//btnLayerUnSel.Enabled = pTocFeatureLayer.Selectable;
contextMenuStrip2.Show(Control.MousePosition);
}
}
}
在axTOCControl1_OnMouseDown事件中,如果点击的是右键,通过pItem == esriTOCControlItem.esriTOCControlItemMap判断一下是不是点击的map,是的话就把contextMenuStrip2给关联上去。
private void 移除所有图层ToolStripMenuItem_Click(object sender, EventArgs e)
{
DialogResult result = MessageBox.Show("是否删除所有图层", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Information);
if (result == DialogResult.OK)
{
axMapControl1.Map.ClearLayers();
ClearPCLayerLock();
axTOCControl1.Update();//更新图层栏图表信息
}
}
然后在contextMenuStrip2新建一个移除所有图层功能,axMapControl1.Map.ClearLayers();,同样使用这句话后,图层栏是不会有任何变化的,需要添加axTOCControl1.Update();
至此这个就差不多做好了。
最后将显示的选择界面和部分代码贴上
public void ShowMap()
{
....//遍历找到了相应的文件
if (sameFile == true)
{
string findFile = findFileName.Substring(0, findFileName.IndexOf('.'));//去除文件名中.shp字符串,目的是为了根据这个名字操作后面的图层组名字
//bool isFindSameLayerGroup = FindSameLyersByName(findFileName);//新建图层组
if (findFile == "ARESIDENTIAL" || findFile == "ASOIL" || findFile == "AVEGETATION" || findFile == "AWATER")
{
if (!isLoadSameLayer(findFile))//如果没有加载相同的图层就加载
{
IGroupLayer groupLayer = new GroupLayerClass();
string layerGroupName = "";//将英文要素名翻译成中文
axMapcontrol.Map.AddLayer(groupLayer);
switch (findFile)
{
case "ARESIDENTIAL": layerGroupName = "居民地";
break;
case "ASOIL": layerGroupName = "土壤";
break;
case "AVEGETATION": layerGroupName = "植被";
break;
case "AWATER": layerGroupName = "水系";
break;
default:
break;
}
groupLayer.Name = layerGroupName;
axMapcontrol.AddShapeFile(path, findFileName);//根据路径和名称添加图层
ILayer getLayer = GetLayersByName(findFile);//根据文件名获得图层栏中相应名字的图层
groupLayer.Add(getLayer);//在图层组中添加这个图层
//这里不用考虑是否需要通过改变其中某一个的图层名来进行删除,因为改变的话他们的图层名都会被改变
DeleteLyersByName(findFile); //删除单独的图层,留下图层组
}
}
else
{
axMapcontrol.AddShapeFile(path, findFileName);
}
}
}
最后成果: