用DotSpatial写了个Shapefile viewer
读大学那会儿老师大概给我们讲过shapefile格式,老师也鼓励我们自己动手写个 Shapefile 解析器,但当时我也不知道干啥了,并没有去了解它,只知道它是个矢量数据格式,而且在gis圈很流行。最近发现 DotSpatial 对 Shapefile 的支持也很完善,而且代码风格简洁,所以想写一篇分享,介绍下 Shapefile 的基本概念和使用方法。
Shapefile 格式快速入门
Shapefile 是 ESRI 在上世纪提出的一种矢量数据格式,虽然资历很老,但在政企与生产环境里依然非常常见(没办法谁让人家进入行业早呢)。它的核心特点是由多文件共同描述同一个图层,最常用的文件包括:
- .shp
- 存储几何形状本体,支持点、折线、多边形等,支持多部件几何,单个文件最大2G
- .shx
- 几何索引文件,加速按记录定位,缺失会影响性能
- .dbf
- 属性表,dBASE 格式,每条几何对应一行属性
- .prj
- 坐标参考信息,WKT 文本,可选但非常重要
- 其他常见伴随文件
- .cpg 指定字符编码
- .sbn .sbx 空间索引等
几个上手就会用到的小知识点:
- 几何类型是固定的
- 一个 Shapefile 图层只能是点图层、线图层或面图层之一
- 坐标系可能缺失
- 没有 .prj 依然能显示,但坐标参考不明确,量测和叠加需要谨慎。说到坐标系,我当年上大学乃至毕业后一两年内都没搞明白是啥玩意(也幸好我没搞明白,不让当时我就可能去了另外一个部门了😂)。
- 属性有长度限制
- .dbf 的字段名和类型有历史限制,适合结构化但不超长的字段
- 优缺点
- 优点是通用、简单、读取速度快
- 缺点是文件分散、字段和编码有限制、不支持拓扑和更丰富的约束
利用 DotSpatial 在 WinForms 中加载并显示shp文件
DotSpatial 是一个用于 .NET 平台的地理信息系统库,支持在 Windows Forms 中显示地图(提供了地图控件),可打开矢量、栅格等空间数据,提供投影转换、符号渲染、属性操作和空间分析等功能。该库采用MIT协议,非常宽松,不过用纯C#做地图渲染,我觉得应该不会有多少公司会这么选择。
下面用 DotSpatial 做一个能打开 Shapefile、浏览地图、选中要素并查看属性的小工具。核心依赖是 DotSpatial.Controls、DotSpatial.Data、DotSpatial.Symbology,必要时可加 DotSpatial.Projections。
先看一眼最终展示效果的截图:
主界面截图:

属性查看截图:

关键代码片段
说实话,WinForms真的太简单了,写个demo非常快(但即便如此,我用Codebuddy还是没能完成这个viewer,最后还得我自己一步一步排查各种问题,AI虽好但也只能打打下手)。 下面用极简代码说明如何把 Map 控件加入 WinForms,并打开一个 .shp 文件显示在地图上。代码仅为示例结构。
using System;
using System.Windows.Forms;
using DotSpatial.Controls;
using DotSpatial.Data;
using DotSpatial.Symbology;
public partial class MainForm : Form
{
private Map m_map;
public MainForm()
{
InitializeComponent();
// Init map control
m_map = new Map();
m_map.Dock = DockStyle.Fill;
Controls.Add(m_map);
}
// Open and render a shapefile
private void OpenShapefile(string path)
{
if (string.IsNullOrWhiteSpace(path))
{
return;
}
IFeatureSet fs = FeatureSet.Open(path);
fs.FillAttributes();
// Add to map and zoom to extent
IMapLayer layer = m_map.Layers.Add(fs);
m_map.ZoomToMaxExtent();
}
}
几点说明:FeatureSet.Open 会读取 .shp 和 .shx,FillAttributes 会加载 .dbf 属性,m_map.Layers.Add 会根据类型应用默认样式,必要时可再用 Symbology 自定义。
如果需要要素选择和右侧属性表展示,可以将 Map 的功能模式切换到 Select,并在选择事件里读取当前选择的要素,然后把属性绑定到一个 PropertyGrid 或 DataGridView。示例伪代码如下:
m_map.FunctionMode = FunctionMode.Select;
private void RefreshSelectedAttributes()
{
var featureLayer = m_map.Layers[0] as IMapFeatureLayer;
if (featureLayer == null)
{
return;
}
var selection = featureLayer.Selection;
}
配合简单的菜单或快捷键,就能完成打开文件、缩放漫游、选中高亮、查看属性等常见工作流。性能方面,大数据量时务必确保 .shx 存在;如果涉及坐标转换,再加上 DotSpatial.Projections 并设置正确的坐标参考,目前没对坐标系处理,只是个简单的demo,所以并没做什么复杂的操作。
地址
DotSpatial: https://github.com/DotSpatial/DotSpatial
ShapefileViewer: https://github.com/AfricChang/ShapefileViewer
完整示例工程包含菜单、工具栏、选择高亮、属性查看、状态栏等功能,适合做成一个轻量的 Shapefile 浏览器(为充分测试,使用需谨慎!)。