最近在搞应用于Windows平板电脑的系统开发,需要开发适用于平板电脑的地图控制控件取代ArcEngine自带的AxTOCContrl。
搞控件开发太费脑啦,需要注意的逻辑关系很复杂 都晕倒啦!
控件实现:地图图层控制(单个控制、图层集控制、整体控制)、图层收缩、控件图层节点拖拽,基本可以替代AE中的AxTocControl。
本控件开发周期为1.5天,解决主要技术问题有节点的动态加载、收缩与展开高度的自动计算、节点控制图层的关闭与打开、节点的拖拽功能。
控件XUTocControl实现,只有三个文件,如图:
图层节点XUBarNode关键代码:
View Code using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Data; using System.Linq; using System.Text; using System.Windows.Forms; using ESRI.ArcGIS.Carto; using ESRI.ArcGIS.Controls; using System.Runtime.InteropServices; namespace GC_Controls { // 定义节点 public partial class XUBarNode : UserControl { // 绑定的图层名 private string _LayerName; // 是否关闭 private bool _IsClose = false ; // 地图窗体 private AxMapControl mapCtrl; #region 定义属性 // 父节点容器 public XUNaviBar ParentBarNode; public string Text { get { return this .NodeLabel.Text; } set { this .NodeLabel.Text = value; } } public Button Close { get { return this .btnClose; } } // 节点字体 public Font TextFont { set { this .NodeLabel.Font = value; } } // 图层值 public string Value { get { return this ._LayerName; } set { this ._LayerName = value; } } #endregion #region 构造函数 public XUBarNode(XUNaviBar ParentBar, string strText) { InitializeComponent(); ParentBarNode = ParentBar; this .Text = strText; mapCtrl = ((AxMapControl)ParentBar.Tag); } public XUBarNode(XUNaviBar ParentBar, string strText, string strValue) : this (ParentBar,strText) { this .Value = strValue; } public XUBarNode(XUNaviBar ParentBar, string strText, string strValue, object tag) : this (ParentBar,strText,strValue) { this .Tag = tag; } #endregion /// <summary> /// 打开关闭图层 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnClose_Click( object sender, EventArgs e) { CloseLayer(_IsClose); mapCtrl.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeography, null , null ); _IsClose = ! _IsClose; } /// <summary> /// 从外部控制:打开或关闭图层 /// </summary> /// <param name="bClose"></param> public void CloseLayer( bool bClose) { if ( ! bClose) { this .btnClose.Text = " 打开 " ; // TODO :关闭图层 if ( this .Tag != null ) { ILayer2 tmpLayer = (ILayer2) this .Tag; tmpLayer.Visible = bClose; } } else { this .btnClose.Text = " 关闭 " ; // TODO :关闭图层 if ( this .Tag != null ) { ILayer2 tmpLayer = (ILayer2) this .Tag; tmpLayer.Visible = bClose; } } } /******************** 下面是实现拖拽的关键代码部分*********************/ private void XUBarNode_MouseDown( object sender, MouseEventArgs e) { // 设置拖拽前的边框类型 this .BorderStyle = BorderStyle.Fixed3D; } /// <summary> /// 获取进入控件里的拖拽进行为类型 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void XUBarNode_DragOver( object sender, DragEventArgs e) { if (e.AllowedEffect == DragDropEffects.Move) { e.Effect = DragDropEffects.Move; } } /// <summary> /// 实现菜单拖拽 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void XUBarNode_DragDrop( object sender, DragEventArgs e) { XUBarNode item = (XUBarNode)e.Data.GetData( typeof (XUBarNode)); item.Dock = DockStyle.Bottom; item.BorderStyle = BorderStyle.FixedSingle; // 获取原来的父节点XUNaviBar,更新节点列表和长度 XUNaviBar parentBar = item.ParentBarNode; parentBar.NodeList.Remove(item); // 重新计算高度 parentBar.Height = parentBar.BarHeight; // 获取当前父节点,并更新列表和长度 XUNaviBar newPBar = this .ParentBarNode; int insertPosition = newPBar.NodeList.IndexOf( this ); newPBar.NodeList.Insert(insertPosition, item); // 重新计算高度 newPBar.Height = newPBar.BarHeight; // 加入控件(TODO:这里当前是将节点插件放在最后端,需要更改) this .Parent.Controls.Add(item); } private void XUBarNode_MouseMove( object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { // 开始对菜单节点项实施拖拽 this .DoDragDrop(sender, DragDropEffects.Move); } } } }父节点XUNaviBar 代码:
View Code namespace GC_Controls { public partial class XUNaviBar : UserControl { #region 定义共有变量 private int _nodeHeight = 30 ; private bool IsExpand = true ; // 地图窗体 private AxMapControl mapCtrl; private XUNaviBar _ParentBar; public ILayer2 CompositeLayer; #endregion #region 定义属性 public ArrayList NodeList = new ArrayList(); public ArrayList BarList = new ArrayList(); public object Tag { get { return mapCtrl; } set { mapCtrl = (AxMapControl)value; } } public string Text { get { return this .BarText.Text; } set { this .BarText.Text = value; } } public int NodeHeight { get { return this ._nodeHeight; } set { this ._nodeHeight = value; } } public int BarHeight { get { if ( ! IsExpand) { this .Height = this .topPanel.Height; } else { this .Height = this .topPanel.Height + this .NodeList.Count * this ._nodeHeight + GetAllBarHeight(); } return this .Height; } set { this .Height += value; } } #endregion public XUNaviBar() { InitializeComponent(); } public XUNaviBar(XUNaviBar parentBar) { // 设置父节点 this ._ParentBar = parentBar; InitializeComponent(); } public XUNaviBar(XUNaviBar parentBar, string layerName): this (parentBar) { this .BarText.Text = layerName; } public XUNaviBar(XUNaviBar parentBar, ILayer2 layer): this (parentBar) { this .BarText.Text = layer.Name; this .CompositeLayer = layer; } /// <summary> /// 添加树形节点BarNode /// </summary> /// <param name="tmp"></param> public void AddBarNode(XUBarNode tmp) { // 设置高度 tmp.Height = this ._nodeHeight; this .NodeList.Add(tmp); // 设置图层节点的高度 this .Height = this .topPanel.Height + this .NodeList.Count * tmp.Height + GetAllBarHeight(); this .contentPanel.Controls.Add(tmp); this .contentPanel.Controls.SetChildIndex(tmp, 0 ); tmp.Dock = DockStyle.Top; if ( ! this .btnClose.Enabled) if ( this .NodeList.Count > 0 ) { this .btnClose.Enabled = true ; this .btnExpand.Enabled = true ; } } /// <summary> /// 添加NaviBar大节点 /// </summary> /// <param name="navBar"></param> public void AddBar(XUNaviBar navBar) { this .BarList.Add(navBar); // 设置图层节点的高度 this .Height = this .topPanel.Height + GetAllBarHeight() + this .NodeList.Count * _nodeHeight; this .contentPanel.Controls.Add(navBar); this .contentPanel.Controls.SetChildIndex(navBar, 0 ); navBar.Dock = DockStyle.Top; if ( ! this .btnClose.Enabled && this .BarList.Count > 0 ) { this .btnClose.Enabled = true ; this .btnExpand.Enabled = true ; } } /// <summary> /// 展开NaviBar下节点 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnExpand_Click( object sender, EventArgs e) { if (IsExpand) { this .Height = this .topPanel.Height; this .btnExpand.Text = " 展开 " ; } else { if ( this .BarList.Count > 0 ) { this .Height = this .topPanel.Height + this .NodeList.Count * this ._nodeHeight + GetAllBarHeight(); } else { this .Height = this .topPanel.Height + this .NodeList.Count * this ._nodeHeight; } this .btnExpand.Text = " 收缩 " ; } if (_ParentBar != null ) { // 补丁,展开父节点时,需执行首节点的该操作 _ParentBar.Height = _ParentBar.BarHeight; this ._ParentBar.Parent.Height = _ParentBar.Height; } IsExpand = ! IsExpand; } /// <summary> /// 获得当前节点高度 /// </summary> /// <returns></returns> private int GetAllBarHeight() { int barHeight = 0 ; foreach (XUNaviBar tmpBar in BarList) { barHeight += tmpBar.Height; } return barHeight; } /// <summary> /// 打开或关闭图层 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnClose_Click( object sender, EventArgs e) { // 图层集合 if ( this .CompositeLayer != null ) { this .CompositeLayer.Visible = ! this .CompositeLayer.Visible; mapCtrl.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeography, null , null ); this .btnClose.Text = this .CompositeLayer.Visible ? " 关闭 " : " 打开 " ; foreach (XUBarNode tmpNode in this .NodeList) { tmpNode.CloseLayer( this .CompositeLayer.Visible); } } else // 顶级图层 { if ( this .btnClose.Text == " 关闭 " ) { CloseLayers( false ); this .btnClose.Text = " 打开 " ; } else { CloseLayers( true ); this .btnClose.Text = " 关闭 " ; } } } // 关闭图层 private void CloseLayers( bool bClose) { // 存在图层集合 if ( this .BarList.Count > 0 ) foreach (XUNaviBar tmpBar in BarList) { tmpBar.CompositeLayer.Visible = bClose; tmpBar.btnClose.Text = bClose ? " 关闭 " : " 打开 " ; foreach (XUBarNode tmpNode in tmpBar.NodeList) { tmpNode.CloseLayer(bClose); } } foreach (XUBarNode tmpNode in this .NodeList) { tmpNode.CloseLayer(bClose); } this .mapCtrl.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeography, null , null ); } private void contentPanel_DragOver( object sender, DragEventArgs e) { if (e.AllowedEffect == DragDropEffects.Move) { e.Effect = DragDropEffects.Move; } } private void contentPanel_DragDrop( object sender, DragEventArgs e) { Control item = (Control)e.Data.GetData( typeof (XUBarNode)); MessageBox.Show( " 1111 " ); this .Controls.Add(item); } private void XUNaviBar_DragOver( object sender, DragEventArgs e) { if (e.AllowedEffect == DragDropEffects.Move) { e.Effect = DragDropEffects.Move; } } private void XUNaviBar_DragDrop( object sender, DragEventArgs e) { Control item = (Control)e.Data.GetData( typeof (XUBarNode)); item.Dock = DockStyle.Bottom; this .contentPanel.Controls.Add(item); } }XUTocControl控件的最终组合代码:
View Code namespace GC_Controls { public partial class XUTocControl : UserControl { private ESRI.ArcGIS.Controls.AxMapControl _MapCtrl; public XUTocControl() { InitializeComponent(); } public XUTocControl(AxMapControl mapCtrl) { InitializeComponent(); _MapCtrl = mapCtrl; InitTOC(mapCtrl.Map, this .MainBar); } /// <summary> /// 初始化图层工具 /// </summary> /// <param name="map"></param> /// <param name="mainBar"></param> private void InitTOC(IMap map,XUNaviBar mainBar) { MainBar.Text = map.Name; // 保存地图对象 MainBar.Tag = _MapCtrl; for ( int j = 0 ; j < map.LayerCount; j ++ ) { ILayer2 pLayer = map.get_Layer(j) as ILayer2; if (pLayer is ESRI.ArcGIS.Carto.IGroupLayer) { ICompositeLayer pCompositelayer; pCompositelayer = (ICompositeLayer)pLayer; XUNaviBar nvBar = new XUNaviBar(mainBar, pLayer); nvBar.Tag = _MapCtrl; int i = 0 ; ILayer2 pLyr; for (i = 0 ; i < pCompositelayer.Count; i ++ ) { pLyr = pCompositelayer.get_Layer(i) as ILayer2; XUBarNode tmpNode = new XUBarNode(nvBar, pLyr.Name, pLyr.Name); // 保存图层对象 tmpNode.Tag = pLyr; nvBar.AddBarNode(tmpNode); } MainBar.AddBar(nvBar); nvBar.Dock = DockStyle.Top; } else { XUBarNode tmpNode = new XUBarNode(mainBar, pLayer.Name, pLayer.Name); // 保存图层对象 tmpNode.Tag = pLayer; MainBar.AddBarNode(tmpNode); } } } private void node_click( object sender, EventArgs e) { _MapCtrl.ActiveView.Refresh(); } }
调用控件的示例代码:该控件使用时,需要ArcEngine 9.3 Runtime.
private void FormTest_Load(object sender, EventArgs e) { this.axMapControl1.LoadMxFile(Application.StartupPath + "\\geodata\tgwGD.mxd"); XUTocControl tocCtrl = new XUTocControl(this.axMapControl1); this.panel1.Controls.Add(tocCtrl); tocCtrl.Dock = DockStyle.Fill;
}
实现控件的节点拖拽功能参照了下列资料,在此表示感谢!
http://bbs.zbitedu.com/viewthread.php?tid=8711
http://www.cnblogs.com/ttc/archive/2008/08/21/1273172.html
http://www.cppblog.com/AutomateProgram/archive/2010/08/26/124890.html
http://kb.cnblogs.com/a/1671126/
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.dodragdrop.aspx#Y6514
此外,WorldWind里也有拖拽文件功能WorldWind学习系列十六:3D Cross Section插件功能分析——TerrainViewer ,拖拽控件和拖拽文件本质上是一样的,只是拖拽控件是将控件作为数据用于传递而已。
本博客声明:本人的技术探索过程中,得到了国信司南公司方面支持。今后,本人博客里的所有技术探索成果将归“无痕客”、“国信司南”和“博客园”三方共同所有,原创作品如需转载,请注明本博客声明。
转载于:https://www.cnblogs.com/wuhenke/archive/2011/05/06/2039488.html
相关资源:VC++ DragTreeControl 可随意拖动节点的树形控件