基于SharpMap和DotNetBar的地图导航(地图缩放滑块)控件开发实践

来源:互联网 发布:梦幻手游猜拳表情源码 编辑:程序博客网 时间:2024/05/22 16:06

    因工作需要,最近想开发一个网络地图下载器,在编码的过程中想到以前谷歌、百度和现在的天地图、ArcGIS里面有一个地图导航控件,就尝试着自己做了一个。其实原理也简单,上下两个按钮,中间一个可上下移动的按钮,下面按钮缩小,上面按钮放大,中间跟随移动或鼠标按住上下拖动。先上图,我做出来的效果是这样的:

 

    这里面还有一个地方要注意,就是导航控件和地图的交互同步,缩放地图时导航控件中间的按钮要跟随上下移动,同样的操作导航控件时,地图要缩放到对应比例级别。

    回到具体实现上来,如果完全使用C#自带的东西设计一个用户控件肯定会复杂一些,有没有现成的控件,只要稍微改写一下就可以呢,答案是肯定的。想到以前用第三方UI控件库DotNetBar的时候有个Slider控件,很符合我们的要求,只要继承改造一下就可以。先上完整代码,等下再来说明。

    一、控件编码部分             

    1.控件(ZoomSlider.cs)源码:

using System;using System.Collections.Generic;using System.ComponentModel;using System.Diagnostics;using System.Linq;using System.Text;using SharpMap;using DevComponents.DotNetBar.Controls;using System.Drawing;namespace SharpMap.Forms{    /// <summary>    /// 自定义地图滑块控件    /// </summary>    public partial class ZoomSilder : Slider    {        private MapBox mapBox;        private List<MapZoom> zoomList;        /// <summary>        /// 缩放级别        /// </summary>        public List<MapZoom> ZoomList        {            get { return this.zoomList; }        }        /// <summary>        /// 初始化设置        /// </summary>        public ZoomSilder()        {            InitializeComponent();            this.DoubleBuffered = true;            this.SliderOrientation = DevComponents.DotNetBar.eOrientation.Vertical;            this.LabelVisible = false;            this.Width = 20;            this.Height = 100;        }        /// <summary>        /// 设置背景透明        /// </summary>        public void SetBackgroundTranspatent()        {            this.BackColor = Color.Transparent;            if (this.mapBox == null) return;            //这行代码很重要            this.Parent = this.mapBox;        }        /// <summary>        /// 设置地图控件        /// </summary>        /// <param name="mapBox"></param>        public void SetMapControl(MapBox mapBox)        {            this.mapBox = mapBox;            //监听地图缩放事件            this.mapBox.MapZoomChanged += new MapBox.MapZoomHandler(mapBox_MapZoomChanged);        }        /// <summary>        /// 地图比例尺改变,滑块跟随移动        /// </summary>        /// <param name="zoom"></param>        void mapBox_MapZoomChanged(double zoom)        {            SetValueToMap(zoom);        }        /// <summary>        /// 设置地图滑块滑动到当前地图        /// </summary>        /// <param name="zoom">当前地图比例尺</param>        public void SetValueToMap(double zoom)        {            if (this.zoomList == null || this.zoomList.Count == 0) return;            this.Invoke((EventHandler)(delegate            {                int level = -1;                if (zoom >= this.zoomList[0].Zoom)                {                    level = this.zoomList[0].Level;                }                else if (zoom <= this.zoomList[this.zoomList.Count - 1].Zoom)                {                    level = this.zoomList[this.zoomList.Count - 1].Level;                }                else                {                    level = GetNearLevelByZoom(zoom);                }                if (level == -1) return;                this.Value = level;            }));        }        /// <summary>        /// 设置比例尺        /// </summary>        /// <param name="zoomList"></param>        public void SetZoomList(List<MapZoom> zoomList)        {            this.zoomList = zoomList;            if (zoomList != null && zoomList.Count != 0)            {                this.Minimum = zoomList[0].Level;                this.Maximum = zoomList[zoomList.Count - 1].Level;                this.Step = 1;            }        }        /// <summary>        /// 重写silder的valuechanged事件        /// </summary>        /// <param name="e"></param>        protected override void OnValueChanged(EventArgs e)        {            base.OnValueChanged(e);            //退出条件,解决地图不能无限放大缩小的问题            if (this.mapBox == null || this.Focused == false || this.ContainsFocus == false                 || this.Capture == false) return;            //缩放地图到地图滑块当前值对应的比例尺            double zoom = GetZoomByLevel(this.Value);            if (zoom == 0.0) return;            this.mapBox.Map.Zoom = zoom;            this.mapBox.Refresh();        }        /// <summary>        /// 根据地图级别获取比例尺        /// </summary>        /// <param name="level"></param>        /// <returns></returns>        public double GetZoomByLevel(int level)        {            double zoom = 0.0;            if (this.zoomList == null || this.zoomList.Count == 0)                return zoom;            foreach (MapZoom item in this.zoomList)            {                if (level == item.Level)                {                    zoom = item.Zoom;                }            }            return zoom;        }        /// <summary>        /// 根据地图当前比例尺获取最接近给定比例尺对应的地图缩放级别        /// </summary>        /// <param name="zoom">地图当前比例尺</param>        /// <returns>最接近给定比例尺的缩放级别</returns>        public int GetNearLevelByZoom(double zoom)        {            int level = -1;            if (this.mapBox == null || this.mapBox.Map == null)                return level;            //取最接近给定比例尺的级别            double minValue = Double.MaxValue;            int minValueIndex = -1;            MapZoom nearZoom = new MapZoom();            for (int i = 0; i < this.zoomList.Count - 1; i++)            {                if (Math.Abs(zoom - this.zoomList[i].Zoom) < minValue)                {                    minValue = Math.Abs(zoom - this.zoomList[i].Zoom);                    minValueIndex = i;                }            }            if (minValueIndex == -1) return level;            level = this.zoomList[minValueIndex].Level;            return level;        }    }}


    2.地图级别、比例尺和分辨率(MapZoom.cs):

using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace SharpMap.Forms{    /// <summary>    /// 地图缩放级别、比例尺和分辨率    /// </summary>    public class MapZoom    {        private int level;        private double zoom;        private double resolution;        public MapZoom() { }        public MapZoom(int level, double zoom, double resolution)        {            this.level = level;            this.zoom = zoom;            this.resolution = resolution;        }        /// <summary>        /// 地图级别        /// </summary>        public int Level        {            get { return this.level; }            set { this.level = value; }        }        /// <summary>        /// 比例尺        /// </summary>        public double Zoom        {            get { return this.zoom; }            set { this.zoom = value; }        }        /// <summary>        /// 分辨率        /// </summary>        public double Resolution        {            get { return this.resolution; }            set { this.resolution = value; }        }    }}


    二、导航控件使用

1.Form_Load事件中:

 

//绑定地图控件this.zoomSilder1.SetMapControl(this.mapBox1);
//设置背景透明this.zoomSilder1.SetBackgroundTranspatent();


    2.设置级别、比例尺和分辨率(以添加Google地图为例,AppUtils.cs):

/// <summary>/// 获取Google地图级别、比例尺和分辨率集合/// </summary>/// <returns></returns>public static List<MapZoom> GetGoogleMapZoomList(){    List<MapZoom> zoomList = new List<MapZoom>();    zoomList.Insert(0, new MapZoom(1, 295828764, 78271.51696));    zoomList.Insert(1, new MapZoom(2, 147914382, 39135.75848));    zoomList.Insert(2, new MapZoom(3, 73957191, 19567.87924));    zoomList.Insert(3, new MapZoom(4, 36978595, 9783.939621));    zoomList.Insert(4, new MapZoom(5, 18489298, 4891.96981));    zoomList.Insert(5, new MapZoom(6, 9244649, 2445.984905));    zoomList.Insert(6, new MapZoom(7, 4622324, 1222.992453));    zoomList.Insert(7, new MapZoom(8, 2311162, 611.4962263));    zoomList.Insert(8, new MapZoom(9, 1155581, 305.7481131));    zoomList.Insert(9, new MapZoom(10, 577791, 152.8740566));    zoomList.Insert(10, new MapZoom(11, 288895, 76.43702829));    zoomList.Insert(11, new MapZoom(12, 144448, 38.21851414));    zoomList.Insert(12, new MapZoom(13, 72224, 19.10925707));    zoomList.Insert(13, new MapZoom(14, 36112, 9.5546285));    zoomList.Insert(14, new MapZoom(15, 18056, 4.7773143));    zoomList.Insert(15, new MapZoom(16, 9028, 2.3886571));    zoomList.Insert(16, new MapZoom(17, 4514, 1.1943286));    zoomList.Insert(17, new MapZoom(18, 2257, 0.59716428));    zoomList.Insert(18, new MapZoom(19, 1128, 0.29858214));    return zoomList;}

    3.添加到地图导航(滑块)控件:

//设置地图滑块缩放级别和比例尺等zoomSilder.SetZoomList(AppUtils.GetGoogleMapZoomList());//滑动到当前比例尺对应的级别zoomSilder.SetValueToMap(mapView.Map.Zoom);//刷新控件zoomSilder.Refresh();


    最后,对几个关键的地方说明一下。

    1.public void SetMapControl(MapBox mapBox),为了使地图导航控件里面能获取地图,并形成互动,必须设置一个公共的方法或属性,将地图控件传入;

    2.public void SetZoomList(List<MapZoom> zoomList),传入地图级别、比例尺和分辨率,这是让导航控件动起来的前提;

    3.protected override void OnValueChanged(EventArgs e),重写Slider控件的值改变事件函数,使操作导航控件,值(地图缩放级别)发生变化时,地图能够跟随缩放;

    4.void mapBox_MapZoomChanged(double zoom),地图级别发生变化时,导航控件滑动到对应的值(地图级别);

    5.public double GetZoomByLevel(int level),根据导航控件的当前值,获取对应的地图比例尺,这样地图控件才知道要怎么缩放;

    6.public int GetNearLevelByZoom(double zoom),根据地图控件当前的比例尺,获取事先设置好的级别、比例尺和分辨率对应关系中最接近的级别。因为地图控件的当前比例尺很难和预设的吻合,而且如果限制死的话,地图控件就只能在预设的比例尺范围内缩放,这样会影响其它图层,如可无无限放大缩小的矢量数据。

 

    最终效果大图:

   

 

2 0