第02章-环境配置与项目创建
第02章:环境配置与项目创建
2.1 开发环境准备
2.1.1 .NET 版本选择
SharpMap 支持多种 .NET 版本:
| .NET 版本 | 支持情况 | 建议 |
|---|---|---|
| .NET Framework 4.6.1+ | 完整支持 | 推荐用于 WinForms 应用 |
| .NET Framework 4.7.2+ | 完整支持 | 推荐用于 WPF 应用 |
| .NET Core 3.1 | 部分支持 | 服务端渲染 |
| .NET 5.0+ | 部分支持 | 服务端渲染 |
| .NET 6.0+ | 部分支持 | 需要 Windows 兼容包 |
注意:SharpMap.UI 组件(MapBox、MapImage)依赖 Windows Forms,因此在非 Windows 平台上只能进行服务端地图渲染。
2.1.2 Visual Studio 配置
推荐版本:Visual Studio 2019 或 Visual Studio 2022
必需的工作负载:
-
.NET 桌面开发
- Windows Forms 应用开发
- WPF 应用开发
-
ASP.NET 和 Web 开发(可选)
- 用于 Web 地图服务开发
安装步骤:
- 打开 Visual Studio Installer
- 选择"修改"当前安装
- 勾选以下工作负载:
- .NET 桌面开发
- ASP.NET 和 Web 开发(可选)
- 确保已安装 .NET Framework 4.7.2 目标包
2.1.3 其他开发工具
JetBrains Rider
- 跨平台 .NET IDE
- 支持 SharpMap 开发
- NuGet 包管理集成
Visual Studio Code
- 轻量级编辑器
- 需要 C# 扩展
- 适合简单项目开发
# VS Code C# 扩展安装
code --install-extension ms-dotnettools.csharp
2.1.4 必需的系统组件
Windows 系统组件:
- GDI+:用于图形渲染(Windows 自带)
- Visual C++ 运行库:如果使用 GDAL 扩展
可选组件:
- GDAL 库:用于栅格数据支持
- PostgreSQL/PostGIS:用于空间数据库访问
2.2 创建 WinForms 项目
2.2.1 使用 Visual Studio 创建项目
步骤 1:创建新项目
- 打开 Visual Studio
- 选择"创建新项目"
- 选择"Windows 窗体应用 (.NET Framework)"
- 点击"下一步"
步骤 2:配置项目
- 项目名称:
SharpMapDemo - 位置:选择适当的文件夹
- 框架:.NET Framework 4.7.2
- 点击"创建"
2.2.2 安装 NuGet 包
通过 NuGet 包管理器:
- 右键点击项目 → "管理 NuGet 程序包"
- 搜索并安装以下包:
SharpMapSharpMap.UI
通过包管理器控制台:
Install-Package SharpMap
Install-Package SharpMap.UI
2.2.3 添加 MapBox 控件到工具箱
步骤 1:打开工具箱
- 在 Visual Studio 中,打开"视图" → "工具箱"
- 右键点击工具箱空白处
- 选择"选择项..."
步骤 2:浏览 SharpMap.UI.dll
- 在"选择工具箱项"对话框中,点击"浏览..."
- 导航到 NuGet 包目录:
packages\SharpMap.UI.1.2.0\lib\net461\SharpMap.UI.dll - 选择该 DLL 文件并点击"打开"
步骤 3:确认添加
- 确认 MapBox 和 MapImage 控件已被勾选
- 点击"确定"
现在您可以在工具箱中看到 MapBox 和 MapImage 控件了。
2.2.4 创建第一个地图窗体
步骤 1:设计窗体
- 打开 Form1.cs [设计]
- 从工具箱拖拽 MapBox 控件到窗体
- 设置 MapBox 的 Dock 属性为 Fill
- 调整窗体大小(如 1024 x 768)
步骤 2:编写代码
using System;
using System.Drawing;
using System.Windows.Forms;
using SharpMap;
using SharpMap.Layers;
using SharpMap.Data.Providers;
using SharpMap.Styles;
namespace SharpMapDemo
{
public partial class Form1 : Form
{
private Map _map;
public Form1()
{
InitializeComponent();
InitializeMap();
}
private void InitializeMap()
{
// 创建地图对象
_map = new Map(mapBox1.Size);
_map.BackColor = Color.White;
// 创建矢量图层
var layer = new VectorLayer("States");
// 设置数据源(请替换为实际的 Shapefile 路径)
string shapeFilePath = @"C:\Data\states.shp";
if (System.IO.File.Exists(shapeFilePath))
{
layer.DataSource = new ShapeFile(shapeFilePath, true);
// 设置样式
layer.Style = new VectorStyle
{
Fill = new SolidBrush(Color.LightGreen),
Outline = new Pen(Color.DarkGreen, 1),
EnableOutline = true
};
// 添加图层到地图
_map.Layers.Add(layer);
// 缩放到全图范围
_map.ZoomToExtents();
}
else
{
MessageBox.Show("请配置正确的 Shapefile 路径!", "提示",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
// 将地图绑定到 MapBox 控件
mapBox1.Map = _map;
// 设置交互模式
mapBox1.ActiveTool = SharpMap.Forms.MapBox.Tools.Pan;
}
}
}
2.2.5 项目文件结构
完整的项目结构应该如下:
SharpMapDemo/
├── SharpMapDemo.csproj
├── App.config
├── packages.config
├── Program.cs
├── Form1.cs
├── Form1.Designer.cs
├── Form1.resx
├── Properties/
│ ├── AssemblyInfo.cs
│ ├── Resources.resx
│ ├── Resources.Designer.cs
│ ├── Settings.settings
│ └── Settings.Designer.cs
└── Data/
├── states.shp
├── states.shx
├── states.dbf
└── states.prj
2.3 创建 WPF 项目
2.3.1 创建 WPF 项目
步骤 1:创建新项目
- 选择"WPF 应用程序 (.NET Framework)"
- 项目名称:
SharpMapWpfDemo - 框架:.NET Framework 4.7.2
步骤 2:安装 NuGet 包
Install-Package SharpMap
2.3.2 创建地图控件
由于 SharpMap 没有原生的 WPF 控件,我们需要使用 WindowsFormsHost 来承载 WinForms 的 MapBox 控件。
步骤 1:添加引用
在项目中添加以下引用:
- WindowsFormsIntegration
- System.Windows.Forms
步骤 2:修改 MainWindow.xaml
<Window x:Class="SharpMapWpfDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
xmlns:wfi="clr-namespace:System.Windows.Forms.Integration;assembly=WindowsFormsIntegration"
xmlns:sm="clr-namespace:SharpMap.Forms;assembly=SharpMap.UI"
Title="SharpMap WPF Demo" Height="600" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- 工具栏 -->
<ToolBar Grid.Row="0">
<Button Content="平移" Click="Pan_Click"/>
<Button Content="放大" Click="ZoomIn_Click"/>
<Button Content="缩小" Click="ZoomOut_Click"/>
<Button Content="全图" Click="ZoomToExtents_Click"/>
</ToolBar>
<!-- 地图控件 -->
<WindowsFormsHost Grid.Row="1" x:Name="mapHost">
<sm:MapBox x:Name="mapBox"/>
</WindowsFormsHost>
<!-- 状态栏 -->
<StatusBar Grid.Row="2">
<StatusBarItem>
<TextBlock x:Name="statusText" Text="就绪"/>
</StatusBarItem>
</StatusBar>
</Grid>
</Window>
步骤 3:编写代码 MainWindow.xaml.cs
using System;
using System.Drawing;
using System.Windows;
using SharpMap;
using SharpMap.Layers;
using SharpMap.Data.Providers;
using SharpMap.Styles;
namespace SharpMapWpfDemo
{
public partial class MainWindow : Window
{
private Map _map;
public MainWindow()
{
InitializeComponent();
InitializeMap();
}
private void InitializeMap()
{
// 创建地图
_map = new Map(new System.Drawing.Size(800, 600));
_map.BackColor = System.Drawing.Color.White;
// 添加图层
string shapeFilePath = @"C:\Data\states.shp";
if (System.IO.File.Exists(shapeFilePath))
{
var layer = new VectorLayer("States");
layer.DataSource = new ShapeFile(shapeFilePath, true);
layer.Style = new VectorStyle
{
Fill = new SolidBrush(System.Drawing.Color.LightBlue),
Outline = new System.Drawing.Pen(System.Drawing.Color.DarkBlue, 1),
EnableOutline = true
};
_map.Layers.Add(layer);
_map.ZoomToExtents();
}
// 绑定到控件
mapBox.Map = _map;
mapBox.ActiveTool = SharpMap.Forms.MapBox.Tools.Pan;
// 监听鼠标移动事件
mapBox.MouseMove += MapBox_MouseMove;
}
private void MapBox_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (_map != null)
{
var worldPos = _map.ImageToWorld(new System.Drawing.PointF(e.X, e.Y));
statusText.Text = $"坐标: {worldPos.X:F6}, {worldPos.Y:F6}";
}
}
private void Pan_Click(object sender, RoutedEventArgs e)
{
mapBox.ActiveTool = SharpMap.Forms.MapBox.Tools.Pan;
}
private void ZoomIn_Click(object sender, RoutedEventArgs e)
{
mapBox.ActiveTool = SharpMap.Forms.MapBox.Tools.ZoomIn;
}
private void ZoomOut_Click(object sender, RoutedEventArgs e)
{
mapBox.ActiveTool = SharpMap.Forms.MapBox.Tools.ZoomOut;
}
private void ZoomToExtents_Click(object sender, RoutedEventArgs e)
{
_map.ZoomToExtents();
mapBox.Refresh();
}
}
}
2.4 创建控制台项目
2.4.1 创建项目
控制台项目适用于服务端地图渲染和批处理任务。
# 使用 dotnet CLI 创建项目
dotnet new console -n SharpMapConsole -f net6.0
# 进入项目目录
cd SharpMapConsole
# 添加 SharpMap 包
dotnet add package SharpMap
# 添加 System.Drawing.Common(.NET Core/5+ 需要)
dotnet add package System.Drawing.Common
2.4.2 基本地图渲染示例
using System;
using System.Drawing;
using System.Drawing.Imaging;
using SharpMap;
using SharpMap.Layers;
using SharpMap.Data.Providers;
using SharpMap.Styles;
class Program
{
static void Main(string[] args)
{
Console.WriteLine("SharpMap 控制台示例");
// 创建地图
var map = new Map(new Size(1024, 768));
map.BackColor = Color.White;
// 添加矢量图层
string shapeFilePath = args.Length > 0 ? args[0] : "data/states.shp";
if (!System.IO.File.Exists(shapeFilePath))
{
Console.WriteLine($"错误:找不到文件 {shapeFilePath}");
return;
}
var layer = new VectorLayer("Data");
layer.DataSource = new ShapeFile(shapeFilePath, true);
layer.Style = new VectorStyle
{
Fill = new SolidBrush(Color.LightYellow),
Outline = new Pen(Color.Black, 1),
EnableOutline = true
};
map.Layers.Add(layer);
// 缩放到全图
map.ZoomToExtents();
// 渲染地图
var image = map.GetMap();
// 保存图片
string outputPath = "output.png";
image.Save(outputPath, ImageFormat.Png);
Console.WriteLine($"地图已保存到:{outputPath}");
Console.WriteLine($"地图范围:{map.Envelope}");
Console.WriteLine($"图层数量:{map.Layers.Count}");
}
}
2.4.3 批量处理示例
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using SharpMap;
using SharpMap.Layers;
using SharpMap.Data.Providers;
using SharpMap.Styles;
using NetTopologySuite.Geometries;
class BatchProcessor
{
static void Main(string[] args)
{
string inputDir = args.Length > 0 ? args[0] : "input";
string outputDir = args.Length > 1 ? args[1] : "output";
// 确保输出目录存在
Directory.CreateDirectory(outputDir);
// 获取所有 Shapefile
var shapeFiles = Directory.GetFiles(inputDir, "*.shp");
Console.WriteLine($"找到 {shapeFiles.Length} 个 Shapefile");
foreach (var shapeFile in shapeFiles)
{
try
{
ProcessShapefile(shapeFile, outputDir);
Console.WriteLine($"处理完成:{Path.GetFileName(shapeFile)}");
}
catch (Exception ex)
{
Console.WriteLine($"处理失败:{Path.GetFileName(shapeFile)} - {ex.Message}");
}
}
Console.WriteLine("批处理完成!");
}
static void ProcessShapefile(string shapeFilePath, string outputDir)
{
var map = new Map(new Size(800, 600));
map.BackColor = Color.White;
var layer = new VectorLayer("Data");
layer.DataSource = new ShapeFile(shapeFilePath, true);
layer.Style = new VectorStyle
{
Fill = new SolidBrush(Color.LightGreen),
Outline = new Pen(Color.DarkGreen, 1),
EnableOutline = true
};
map.Layers.Add(layer);
map.ZoomToExtents();
var image = map.GetMap();
string outputFileName = Path.GetFileNameWithoutExtension(shapeFilePath) + ".png";
string outputPath = Path.Combine(outputDir, outputFileName);
image.Save(outputPath, ImageFormat.Png);
}
}
2.5 创建 ASP.NET 项目
2.5.1 创建 ASP.NET Core Web API 项目
dotnet new webapi -n SharpMapWebApi
cd SharpMapWebApi
dotnet add package SharpMap
dotnet add package System.Drawing.Common
2.5.2 创建地图服务控制器
using Microsoft.AspNetCore.Mvc;
using System.Drawing;
using System.Drawing.Imaging;
using SharpMap;
using SharpMap.Layers;
using SharpMap.Data.Providers;
using SharpMap.Styles;
using NetTopologySuite.Geometries;
namespace SharpMapWebApi.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class MapController : ControllerBase
{
private readonly string _dataPath;
public MapController(IConfiguration configuration)
{
_dataPath = configuration["MapData:Path"] ?? "Data";
}
/// <summary>
/// 获取地图图片
/// </summary>
[HttpGet("image")]
public IActionResult GetMapImage(
[FromQuery] int width = 800,
[FromQuery] int height = 600,
[FromQuery] double? minX = null,
[FromQuery] double? minY = null,
[FromQuery] double? maxX = null,
[FromQuery] double? maxY = null)
{
try
{
var map = CreateMap(width, height);
// 如果指定了范围,则使用指定范围
if (minX.HasValue && minY.HasValue && maxX.HasValue && maxY.HasValue)
{
map.ZoomToBox(new Envelope(minX.Value, maxX.Value, minY.Value, maxY.Value));
}
else
{
map.ZoomToExtents();
}
var image = map.GetMap();
using (var stream = new MemoryStream())
{
image.Save(stream, ImageFormat.Png);
return File(stream.ToArray(), "image/png");
}
}
catch (Exception ex)
{
return BadRequest(new { error = ex.Message });
}
}
/// <summary>
/// 获取地图范围
/// </summary>
[HttpGet("extent")]
public IActionResult GetMapExtent()
{
try
{
var map = CreateMap(100, 100);
map.ZoomToExtents();
return Ok(new
{
minX = map.Envelope.MinX,
minY = map.Envelope.MinY,
maxX = map.Envelope.MaxX,
maxY = map.Envelope.MaxY
});
}
catch (Exception ex)
{
return BadRequest(new { error = ex.Message });
}
}
/// <summary>
/// 获取图层列表
/// </summary>
[HttpGet("layers")]
public IActionResult GetLayers()
{
try
{
var shapeFiles = Directory.GetFiles(_dataPath, "*.shp");
var layers = shapeFiles.Select(f => new
{
name = Path.GetFileNameWithoutExtension(f),
path = f
});
return Ok(layers);
}
catch (Exception ex)
{
return BadRequest(new { error = ex.Message });
}
}
private Map CreateMap(int width, int height)
{
var map = new Map(new Size(width, height));
map.BackColor = Color.White;
// 添加所有 Shapefile 图层
var shapeFiles = Directory.GetFiles(_dataPath, "*.shp");
foreach (var shapeFile in shapeFiles)
{
var layerName = Path.GetFileNameWithoutExtension(shapeFile);
var layer = new VectorLayer(layerName);
layer.DataSource = new ShapeFile(shapeFile, true);
layer.Style = GetDefaultStyle();
map.Layers.Add(layer);
}
return map;
}
private VectorStyle GetDefaultStyle()
{
return new VectorStyle
{
Fill = new SolidBrush(Color.FromArgb(150, 144, 238, 144)),
Outline = new Pen(Color.DarkGreen, 1),
EnableOutline = true
};
}
}
}
2.5.3 配置 appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"MapData": {
"Path": "Data"
}
}
2.6 测试数据准备
2.6.1 下载测试数据
SharpMap Wiki 提供了测试数据下载:
# 下载 states_ugl.zip
wget https://github.com/SharpMap/SharpMap/wiki/resources/states_ugl.zip
# 解压到 Data 目录
unzip states_ugl.zip -d Data/
2.6.2 常用的公开数据源
-
Natural Earth
- 网址:https://www.naturalearthdata.com/
- 提供全球行政区划、河流、道路等数据
-
OpenStreetMap
- 网址:https://download.geofabrik.de/
- 提供全球街道地图数据
-
GADM
- 网址:https://gadm.org/
- 提供全球行政区划边界
2.6.3 创建测试数据目录结构
项目目录/
├── Data/
│ ├── Vector/
│ │ ├── countries.shp
│ │ ├── states.shp
│ │ └── cities.shp
│ ├── Raster/
│ │ ├── dem.tif
│ │ └── satellite.tif
│ └── Tiles/
│ └── cache/
2.7 项目配置最佳实践
2.7.1 配置文件管理
App.config / appsettings.json 示例:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<!-- 数据路径配置 -->
<add key="DataPath" value="Data"/>
<add key="CachePath" value="Cache"/>
<!-- 地图默认设置 -->
<add key="DefaultSRID" value="4326"/>
<add key="DefaultMapWidth" value="800"/>
<add key="DefaultMapHeight" value="600"/>
<!-- 数据库连接 -->
<add key="PostGISConnection" value="Host=localhost;Database=gis;Username=user;Password=pass"/>
</appSettings>
</configuration>
2.7.2 依赖注入配置
// Services/MapService.cs
public interface IMapService
{
Map CreateMap(int width, int height);
Image RenderMap(Map map);
}
public class MapService : IMapService
{
private readonly IConfiguration _configuration;
public MapService(IConfiguration configuration)
{
_configuration = configuration;
}
public Map CreateMap(int width, int height)
{
var map = new Map(new Size(width, height));
map.BackColor = Color.White;
return map;
}
public Image RenderMap(Map map)
{
return map.GetMap();
}
}
// Program.cs 或 Startup.cs
services.AddSingleton<IMapService, MapService>();
2.7.3 日志配置
using Microsoft.Extensions.Logging;
public class MapController : ControllerBase
{
private readonly ILogger<MapController> _logger;
private readonly IMapService _mapService;
public MapController(ILogger<MapController> logger, IMapService mapService)
{
_logger = logger;
_mapService = mapService;
}
[HttpGet("image")]
public IActionResult GetMapImage()
{
_logger.LogInformation("开始渲染地图...");
try
{
var map = _mapService.CreateMap(800, 600);
// ...
_logger.LogInformation("地图渲染完成");
return File(/* ... */);
}
catch (Exception ex)
{
_logger.LogError(ex, "地图渲染失败");
return StatusCode(500);
}
}
}
2.8 常见问题与解决方案
2.8.1 NuGet 包安装问题
问题:安装 SharpMap 时出现依赖冲突
解决方案:
# 清理 NuGet 缓存
dotnet nuget locals all --clear
# 重新安装
Install-Package SharpMap -Force
2.8.2 程序集引用问题
问题:找不到 SharpMap.UI 中的控件
解决方案:
- 确保已安装 SharpMap.UI 包
- 重新构建项目
- 手动添加工具箱项
2.8.3 运行时错误
问题:System.Drawing 相关异常
解决方案:
// 在 .NET Core/5+ 项目中,需要确保启用了 System.Drawing.Common
// 在 runtimeconfig.json 中添加:
{
"runtimeOptions": {
"configProperties": {
"System.Drawing.EnableUnixSupport": true
}
}
}
2.8.4 跨平台问题
问题:在 Linux 上运行 SharpMap
解决方案:
# 安装 libgdiplus
# Ubuntu/Debian
sudo apt-get install libgdiplus
# CentOS/RHEL
sudo yum install libgdiplus
# macOS
brew install mono-libgdiplus
2.9 本章小结
本章详细介绍了 SharpMap 开发环境的配置和项目创建:
- 环境准备:了解了 .NET 版本选择和开发工具配置
- WinForms 项目:创建了基本的 WinForms 地图应用
- WPF 项目:学习了如何在 WPF 中使用 SharpMap
- 控制台项目:实现了服务端地图渲染
- ASP.NET 项目:创建了地图 Web 服务
- 测试数据:准备了测试数据和目录结构
- 最佳实践:了解了项目配置和依赖注入
2.10 参考资源
下一章预告:第03章将深入讲解 SharpMap 的核心架构和类库设计,包括 Map 类、图层类、数据提供者等核心组件的详细介绍。

浙公网安备 33010602011771号