第15章 - 各平台集成实战
第15章:各平台集成实战
15.1 WPF 集成
15.1.1 MVVM 模式集成
// MapViewModel.cs
public class MapViewModel : INotifyPropertyChanged
{
private Map _map;
public Map Map
{
get => _map;
set
{
_map = value;
OnPropertyChanged();
}
}
public MapViewModel()
{
InitializeMap();
}
private void InitializeMap()
{
Map = new Map();
Map.Layers.Add(OpenStreetMap.CreateTileLayer());
// 添加数据图层
var dataLayer = new MemoryLayer { Name = "Data" };
Map.Layers.Add(dataLayer);
}
public ICommand ZoomInCommand => new RelayCommand(() => Map.Navigator.ZoomIn());
public ICommand ZoomOutCommand => new RelayCommand(() => Map.Navigator.ZoomOut());
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
<!-- MainWindow.xaml -->
<Window x:Class="WpfApp.MainWindow"
xmlns:mapsui="clr-namespace:Mapsui.UI.Wpf;assembly=Mapsui.UI.Wpf">
<Window.DataContext>
<local:MapViewModel/>
</Window.DataContext>
<Grid>
<mapsui:MapControl Map="{Binding Map}"/>
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Margin="10">
<Button Content="+" Command="{Binding ZoomInCommand}" Width="30"/>
<Button Content="-" Command="{Binding ZoomOutCommand}" Width="30"/>
</StackPanel>
</Grid>
</Window>
15.1.2 WPF 特有功能
// 获取 WPF 特有的 MapControl 属性
var wpfMapControl = mapControl as Mapsui.UI.Wpf.MapControl;
// 处理 WPF 鼠标事件
wpfMapControl.MouseLeftButtonDown += (s, e) =>
{
var position = e.GetPosition(wpfMapControl);
var worldPosition = wpfMapControl.Viewport.ScreenToWorld(
new MPoint(position.X, position.Y)
);
// 处理点击
};
15.2 MAUI 集成
15.2.1 MAUI 应用结构
// MauiProgram.cs
using SkiaSharp.Views.Maui.Controls.Hosting;
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.UseSkiaSharp() // 必须添加
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
});
return builder.Build();
}
15.2.2 MAUI 地图页面
// MapPage.xaml.cs
public partial class MapPage : ContentPage
{
private readonly MapControl _mapControl;
public MapPage()
{
InitializeComponent();
_mapControl = new MapControl();
InitializeMap();
Content = CreateLayout();
}
private void InitializeMap()
{
var map = _mapControl.Map;
map.Layers.Add(OpenStreetMap.CreateTileLayer());
// MAUI 平台的位置服务集成
#if ANDROID || IOS
RequestLocationPermission();
#endif
}
private View CreateLayout()
{
return new Grid
{
Children =
{
_mapControl,
new StackLayout
{
Orientation = StackOrientation.Horizontal,
HorizontalOptions = LayoutOptions.End,
VerticalOptions = LayoutOptions.Start,
Margin = new Thickness(10),
Children =
{
new Button { Text = "+", Command = new Command(ZoomIn) },
new Button { Text = "-", Command = new Command(ZoomOut) }
}
}
}
};
}
private void ZoomIn() => _mapControl.Map.Navigator.ZoomIn();
private void ZoomOut() => _mapControl.Map.Navigator.ZoomOut();
private async void RequestLocationPermission()
{
var status = await Permissions.RequestAsync<Permissions.LocationWhenInUse>();
if (status == PermissionStatus.Granted)
{
// 启用位置追踪
}
}
}
15.3 Avalonia 集成
15.3.1 Avalonia MVVM
// MainWindowViewModel.cs
public class MainWindowViewModel : ViewModelBase
{
private Map _map;
public Map Map
{
get => _map;
set => this.RaiseAndSetIfChanged(ref _map, value);
}
public MainWindowViewModel()
{
Map = new Map();
Map.Layers.Add(OpenStreetMap.CreateTileLayer());
}
public void ZoomIn() => Map.Navigator.ZoomIn();
public void ZoomOut() => Map.Navigator.ZoomOut();
}
<!-- MainWindow.axaml -->
<Window xmlns="https://github.com/avaloniaui"
xmlns:mapsui="clr-namespace:Mapsui.UI.Avalonia;assembly=Mapsui.UI.Avalonia">
<Grid>
<mapsui:MapControl Map="{Binding Map}"/>
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Margin="10">
<Button Content="+" Command="{Binding ZoomInCommand}"/>
<Button Content="-" Command="{Binding ZoomOutCommand}"/>
</StackPanel>
</Grid>
</Window>
15.4 Blazor 集成
15.4.1 Blazor WebAssembly
@page "/map"
@using Mapsui.UI.Blazor
@using Mapsui.Tiling
<div class="map-container">
<MapControlComponent @ref="_mapControl" />
<div class="map-controls">
<button @onclick="ZoomIn">+</button>
<button @onclick="ZoomOut">-</button>
</div>
</div>
<style>
.map-container {
position: relative;
width: 100%;
height: 80vh;
}
.map-container canvas {
width: 100%;
height: 100%;
}
.map-controls {
position: absolute;
top: 10px;
right: 10px;
}
</style>
@code {
private MapControl? _mapControl;
protected override void OnAfterRender(bool firstRender)
{
if (firstRender && _mapControl != null)
{
_mapControl.Map?.Layers.Add(OpenStreetMap.CreateTileLayer());
}
}
private void ZoomIn() => _mapControl?.Map?.Navigator.ZoomIn();
private void ZoomOut() => _mapControl?.Map?.Navigator.ZoomOut();
}
15.4.2 Blazor Server
@page "/map"
@using Mapsui.UI.Blazor
@inject IJSRuntime JSRuntime
<MapControlComponent @ref="_mapControl" />
@code {
private MapControl? _mapControl;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender && _mapControl != null)
{
await InitializeMapAsync();
}
}
private async Task InitializeMapAsync()
{
// Blazor Server 可能需要异步初始化
await Task.Run(() =>
{
_mapControl?.Map?.Layers.Add(OpenStreetMap.CreateTileLayer());
});
}
}
15.5 Windows Forms 集成
15.5.1 基本集成
public partial class MapForm : Form
{
private MapControl _mapControl;
public MapForm()
{
InitializeComponent();
InitializeMap();
}
private void InitializeMap()
{
_mapControl = new MapControl
{
Dock = DockStyle.Fill
};
_mapControl.Map.Layers.Add(OpenStreetMap.CreateTileLayer());
Controls.Add(_mapControl);
// 添加工具栏
var toolStrip = new ToolStrip
{
Items =
{
new ToolStripButton("放大", null, (s, e) => _mapControl.Map.Navigator.ZoomIn()),
new ToolStripButton("缩小", null, (s, e) => _mapControl.Map.Navigator.ZoomOut())
}
};
Controls.Add(toolStrip);
}
}
15.6 移动平台集成
15.6.1 Android 特定配置
// MainActivity.cs
[Activity(Label = "@string/app_name", MainLauncher = true)]
public class MainActivity : Activity
{
private MapControl _mapControl;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.Main);
_mapControl = FindViewById<MapControl>(Resource.Id.mapcontrol);
var map = new Map();
map.Layers.Add(OpenStreetMap.CreateTileLayer());
_mapControl.Map = map;
// 请求位置权限
RequestLocationPermission();
}
private void RequestLocationPermission()
{
if (CheckSelfPermission(Manifest.Permission.AccessFineLocation)
!= Permission.Granted)
{
RequestPermissions(
new[] { Manifest.Permission.AccessFineLocation },
1
);
}
}
}
15.6.2 iOS 特定配置
// ViewController.cs
public class ViewController : UIViewController
{
private MapControl _mapControl;
public override void ViewDidLoad()
{
base.ViewDidLoad();
_mapControl = new MapControl(View.Bounds);
var map = new Map();
map.Layers.Add(OpenStreetMap.CreateTileLayer());
_mapControl.Map = map;
View = _mapControl;
// 请求位置权限
RequestLocationAuthorization();
}
private void RequestLocationAuthorization()
{
var locationManager = new CLLocationManager();
locationManager.RequestWhenInUseAuthorization();
}
}
15.7 跨平台代码共享
15.7.1 共享业务逻辑
// Shared/MapService.cs (放在共享项目中)
public class MapService
{
public Map CreateMap()
{
var map = new Map();
// 添加底图
map.Layers.Add(OpenStreetMap.CreateTileLayer());
// 添加数据图层
var dataLayer = new MemoryLayer { Name = "Data" };
map.Layers.Add(dataLayer);
// 添加小部件
map.Widgets.Add(new ScaleBarWidget(map));
return map;
}
public void AddMarker(Map map, double lon, double lat, string label)
{
var layer = map.Layers.FindLayer("Data") as MemoryLayer;
if (layer == null) return;
var point = SphericalMercator.FromLonLat(lon, lat).ToMPoint();
var feature = new PointFeature(point);
feature["label"] = label;
// 更新图层
var features = layer.Features?.ToList() ?? new List<IFeature>();
features.Add(feature);
layer.Features = features;
layer.DataHasChanged();
}
}
15.7.2 平台适配接口
// ILocationService.cs
public interface ILocationService
{
Task<(double Lon, double Lat)?> GetCurrentLocationAsync();
void StartTracking(Action<double, double> onLocationChanged);
void StopTracking();
}
// Android 实现
public class AndroidLocationService : ILocationService
{
// Android 特定实现
}
// iOS 实现
public class iOSLocationService : ILocationService
{
// iOS 特定实现
}
15.8 本章小结
本章详细介绍了 Mapsui 在各平台的集成:
- WPF 集成:MVVM 模式、数据绑定
- MAUI 集成:跨平台移动应用
- Avalonia 集成:跨平台桌面应用
- Blazor 集成:Web 应用
- Windows Forms 集成:传统桌面应用
- 移动平台:Android 和 iOS 特定配置
- 跨平台代码共享:业务逻辑共享和平台适配
在下一章中,我们将通过实战案例综合运用所学知识。
15.9 思考与练习
- 创建一个 MAUI 应用,支持 Android 和 iOS 位置追踪。
- 实现一个 Blazor 地图应用,支持地图搜索功能。
- 使用 Avalonia 创建一个支持 Windows、macOS 和 Linux 的地图应用。
- 设计一个跨平台的地图 SDK,抽象平台差异。
- 实现一个离线地图功能,在各平台上都能工作。

浙公网安备 33010602011771号