• 打造自己地图AxTOCContrl树形控件——XUTocControl(成功解决节点控件拖拽问题)


       最近在搞应用于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, 
    nullnull);
                _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, 
    nullnull);
                    
    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, nullnull);
            }


            
    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 ,拖拽控件和拖拽文件本质上是一样的,只是拖拽控件是将控件作为数据用于传递而已。

           本博客声明:本人的技术探索过程中,得到了国信司南公司方面支持。今后,本人博客里的所有技术探索成果将归“无痕客”、“国信司南”和“博客园”三方共同所有,原创作品如需转载,请注明本博客声明。

      

  • 相关阅读:
    数据库字典
    目录结构-模板目录
    vuex
    innerHTML,innertext,textContent区别
    组件传值
    深拷贝和浅拷贝
    关于element ui头像上传问题
    常用的字符串截取的方法
    接口报错之number值过大问题
    node_modules?
  • 原文地址:https://www.cnblogs.com/wuhenke/p/2039488.html
Copyright © 2020-2023  润新知