目录核心逻辑梳理方式 1WebBrowser 实现双向交互入门级步骤 1修改百度地图 HTML新增点击事件 批量加标记方法步骤 2WinForm 端代码接收坐标 调用批量加标记2.1 定义供 JS 调用的通信类必须加[ComVisible(true)]2.2 Form1.cs 完整代码含 UI 控件 核心逻辑2.3 安装 JSON 序列化包必须步骤 3测试运行方式 2CefSharp 实现双向交互推荐Chrome 内核步骤 1安装 CefSharp同之前步骤 2修改 HTML仅需微调核心逻辑不变步骤 3WinForm 端完整代码CefSharp 版步骤 4测试运行关键知识点详解1. 双向通信核心原理2. 新手常见坑3. 扩展功能建议总结核心要点回顾后续扩展在 WinForm 中实现与百度地图的双向交互接收地图点击的经纬度、批量添加设备标记我会分「WebBrowser入门无依赖」和「CefSharp推荐兼容性更好」两种方式提供完整代码每个示例都包含详细注释和关键逻辑讲解确保你能直接运行并理解。核心逻辑梳理地图→WinForm点击传坐标在百度地图 JS 代码中监听点击事件将经纬度通过「JS 调用 C# 方法」的方式传回 WinFormWinForm→地图批量加标记WinForm 构造设备坐标数据调用地图 JS 方法批量创建标记点并显示在地图上两种方式的核心差异WebBrowser 通过ObjectForScripting实现通信CefSharp 通过Javascript Binding实现更灵活的双向通信。方式 1WebBrowser 实现双向交互入门级步骤 1修改百度地图 HTML新增点击事件 批量加标记方法替换之前的BaiduMap.html确保替换你的百度AK!DOCTYPE html html langzh-CN head meta charsetutf-8 / script typetext/javascript srchttp://api.map.baidu.com/api?v3.0ak你的百度AK/script style html, body { width: 100%; height: 100%; margin: 0; padding: 0; } #mapContainer { width: 100%; height: 100%; } /style /head body div idmapContainer/div script typetext/javascript // 全局地图实例方便后续调用 var mapInstance null; // 存储所有设备标记方便后续清理 var deviceMarkers []; // 初始化地图 function initMap() { mapInstance new BMapGL.Map(mapContainer); var centerPoint new BMapGL.Point(116.404, 39.915); // 北京天安门 mapInstance.centerAndZoom(centerPoint, 12); mapInstance.enableScrollWheelZoom(true); mapInstance.addControl(new BMapGL.NavigationControl()); mapInstance.addControl(new BMapGL.ScaleControl()); // 监听地图点击事件将经纬度传回WinForm mapInstance.addEventListener(click, function (e) { var lng e.point.lng.toFixed(6); // 经度保留6位小数 var lat e.point.lat.toFixed(6); // 纬度 // 调用WinForm暴露的方法window.external对应ObjectForScripting if (window.external typeof window.external.OnMapClicked function) { window.external.OnMapClicked(lng, lat); // 传经纬度给WinForm } }); } // 批量添加设备标记供WinForm调用 function addDeviceMarkers(devices) { // 先清空原有标记 clearAllDeviceMarkers(); if (!mapInstance || !devices || devices.length 0) return; // 遍历设备列表创建标记 for (var i 0; i devices.length; i) { var device devices[i]; var point new BMapGL.Point(device.Lng, device.Lat); // 创建标记 var marker new BMapGL.Marker(point); // 标记添加点击提示显示设备信息 var infoWindow new BMapGL.InfoWindow( div stylefont-size:14px; p设备ID${device.Id}/p p设备名称${device.Name}/p p坐标${device.Lng}, ${device.Lat}/p /div ); marker.addEventListener(click, function () { this.openInfoWindow(infoWindow); }); // 添加标记到地图 mapInstance.addOverlay(marker); // 保存标记到数组方便后续清理 deviceMarkers.push(marker); } // 自动调整地图视野显示所有标记 var points devices.map(d new BMapGL.Point(d.Lng, d.Lat)); var view new BMapGL.Viewport(mapInstance, points); view.resize(); mapInstance.setViewport(points); } // 清空所有设备标记 function clearAllDeviceMarkers() { for (var i 0; i deviceMarkers.length; i) { mapInstance.removeOverlay(deviceMarkers[i]); } deviceMarkers []; } window.onload initMap; /script /body /html步骤 2WinForm 端代码接收坐标 调用批量加标记2.1 定义供 JS 调用的通信类必须加[ComVisible(true)]在 Form1.cs 同级新建MapCommunicator.csusing System; using System.Runtime.InteropServices; using System.Windows.Forms; // 必须添加ComVisible特性否则JS无法调用 [ComVisible(true)] public class MapCommunicator { // 定义坐标点击事件供Form1订阅 public event Actionstring, string OnMapClicked; // 供JS调用的方法接收地图点击的经纬度 public void OnMapClicked(string lng, string lat) { // 触发事件让Form1处理 OnMapClicked?.Invoke(lng, lat); } }2.2 Form1.cs 完整代码含 UI 控件 核心逻辑csharp运行using System; using System.Collections.Generic; using System.IO; using System.Windows.Forms; namespace WinFormBaiduMap { public partial class Form1 : Form { // 地图通信器供JS调用 private MapCommunicator _mapComm; // 模拟设备数据 private ListDeviceModel _deviceList; public Form1() { InitializeComponent(); // 初始化UI控件手动添加无需设计器 InitUI(); // 初始化地图通信器 _mapComm new MapCommunicator(); _mapComm.OnMapClicked MapComm_OnMapClicked; // 绑定WebBrowser的JS通信对象 webBrowserMap.ObjectForScripting _mapComm; // 初始化模拟设备数据 InitDeviceData(); // 加载地图 LoadBaiduMap(); } #region UI初始化手动添加控件新手可直接复制 private WebBrowser webBrowserMap; private TextBox txtLng; private TextBox txtLat; private Button btnAddDevices; private Button btnClearMarkers; private void InitUI() { // 1. WebBrowser控件占满大部分区域 webBrowserMap new WebBrowser { Dock DockStyle.Fill, Name webBrowserMap }; // 2. 底部面板显示坐标按钮 Panel panelBottom new Panel { Dock DockStyle.Bottom, Height 80, BackColor Color.LightGray }; // 坐标显示控件 Label lblLng new Label { Text 经度, Location new Point(20, 20), AutoSize true }; txtLng new TextBox { Location new Point(60, 20), Width 150, ReadOnly true }; Label lblLat new Label { Text 纬度, Location new Point(230, 20), AutoSize true }; txtLat new TextBox { Location new Point(270, 20), Width 150, ReadOnly true }; // 功能按钮 btnAddDevices new Button { Text 批量添加设备标记, Location new Point(440, 20), Width 120 }; btnAddDevices.Click BtnAddDevices_Click; btnClearMarkers new Button { Text 清空所有标记, Location new Point(570, 20), Width 100 }; btnClearMarkers.Click BtnClearMarkers_Click; // 添加控件到面板 panelBottom.Controls.Add(lblLng); panelBottom.Controls.Add(txtLng); panelBottom.Controls.Add(lblLat); panelBottom.Controls.Add(txtLat); panelBottom.Controls.Add(btnAddDevices); panelBottom.Controls.Add(btnClearMarkers); // 添加控件到窗体 this.Controls.Add(webBrowserMap); this.Controls.Add(panelBottom); this.Text WinForm百度地图WebBrowser; this.Size new Size(1000, 700); // 设置WebBrowser使用IE11内核关键 SetWebBrowserIEVersion(); } #endregion #region 核心功能实现 /// summary /// 加载百度地图HTML /// /summary private void LoadBaiduMap() { try { string htmlPath Path.Combine(AppDomain.CurrentDomain.BaseDirectory, BaiduMap.html); webBrowserMap.Url new Uri(htmlPath); } catch (Exception ex) { MessageBox.Show(地图加载失败 ex.Message); } } /// summary /// 接收地图点击的坐标显示到文本框 /// /summary private void MapComm_OnMapClicked(string lng, string lat) { // 跨线程更新UIJS调用可能在非UI线程 if (this.InvokeRequired) { this.Invoke(new Actionstring, string(MapComm_OnMapClicked), lng, lat); return; } txtLng.Text lng; txtLat.Text lat; MessageBox.Show($你点击了地图\n经度{lng}\n纬度{lat}); } /// summary /// 批量添加设备标记点击按钮触发 /// /summary private void BtnAddDevices_Click(object sender, EventArgs e) { if (webBrowserMap.Document null) return; try { // 将C#的设备列表转为JS可识别的格式JSON string devicesJson Newtonsoft.Json.JsonConvert.SerializeObject(_deviceList); // 调用HTML中的addDeviceMarkers方法 webBrowserMap.Document.InvokeScript(addDeviceMarkers, new object[] { devicesJson }); MessageBox.Show($成功添加 {_deviceList.Count} 个设备标记); } catch (Exception ex) { MessageBox.Show(添加标记失败 ex.Message); } } /// summary /// 清空所有设备标记 /// /summary private void BtnClearMarkers_Click(object sender, EventArgs e) { if (webBrowserMap.Document null) return; webBrowserMap.Document.InvokeScript(clearAllDeviceMarkers); MessageBox.Show(已清空所有设备标记); } /// summary /// 初始化模拟设备数据实际项目可从数据库/串口读取 /// /summary private void InitDeviceData() { _deviceList new ListDeviceModel { new DeviceModel { Id 1, Name 风速计-1, Lng 116.3907, Lat 39.9128 }, new DeviceModel { Id 2, Name 风速计-2, Lng 116.4102, Lat 39.9085 }, new DeviceModel { Id 3, Name 温湿度计-1, Lng 116.4058, Lat 39.9201 }, new DeviceModel { Id 4, Name 气压计-1, Lng 116.3895, Lat 39.9156 } }; } /// summary /// 设置WebBrowser使用IE11内核 /// /summary private void SetWebBrowserIEVersion() { try { var key Microsoft.Win32.Registry.CurrentUser.OpenSubKey( Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION, true); string appName System.Diagnostics.Process.GetCurrentProcess().ProcessName .exe; key.SetValue(appName, 11001, Microsoft.Win32.RegistryValueKind.DWord); key.Close(); } catch { } } #endregion // 设备模型类与HTML中的设备结构对应 public class DeviceModel { public int Id { get; set; } // 设备ID public string Name { get; set; } // 设备名称 public double Lng { get; set; } // 经度 public double Lat { get; set; } // 纬度 } } }2.3 安装 JSON 序列化包必须右键项目 → 管理 NuGet 程序包 → 搜索Newtonsoft.Json→ 安装用于将 C# 对象转为 JS 可识别的 JSON。步骤 3测试运行确保BaiduMap.html的「复制到输出目录」设为「始终复制」按 F5 启动点击地图任意位置 → WinForm 文本框显示经纬度弹出提示点击「批量添加设备标记」→ 地图显示 4 个设备标记点击标记可查看设备信息点击「清空所有标记」→ 地图上的设备标记全部消失。方式 2CefSharp 实现双向交互推荐Chrome 内核步骤 1安装 CefSharp同之前NuGet 安装CefSharp.WinForms项目属性→生成→平台目标设为x64取消「首选 32 位」。步骤 2修改 HTML仅需微调核心逻辑不变只需将地图点击事件中的window.external改为window.cefSharpCommCefSharp 绑定的对象名// 地图点击事件修改这一段 mapInstance.addEventListener(click, function (e) { var lng e.point.lng.toFixed(6); var lat e.point.lat.toFixed(6); // CefSharp通信对象替换window.external if (window.cefSharpComm typeof window.cefSharpComm.OnMapClicked function) { window.cefSharpComm.OnMapClicked(lng, lat); } });步骤 3WinForm 端完整代码CefSharp 版using System; using System.Collections.Generic; using System.IO; using System.Windows.Forms; using CefSharp; using CefSharp.WinForms; using Newtonsoft.Json; namespace WinFormBaiduMap { public partial class Form1 : Form { private ChromiumWebBrowser _chromeBrowser; private ListDeviceModel _deviceList; public Form1() { InitializeComponent(); InitUI(); InitCefSharp(); InitDeviceData(); LoadBaiduMapWithCefSharp(); } #region UI初始化和WebBrowser版一致 private Panel panelBottom; private TextBox txtLng; private TextBox txtLat; private Button btnAddDevices; private Button btnClearMarkers; private void InitUI() { // 底部面板坐标按钮 panelBottom new Panel { Dock DockStyle.Bottom, Height 80, BackColor Color.LightGray }; Label lblLng new Label { Text 经度, Location new Point(20, 20), AutoSize true }; txtLng new TextBox { Location new Point(60, 20), Width 150, ReadOnly true }; Label lblLat new Label { Text 纬度, Location new Point(230, 20), AutoSize true }; txtLat new TextBox { Location new Point(270, 20), Width 150, ReadOnly true }; btnAddDevices new Button { Text 批量添加设备标记, Location new Point(440, 20), Width 120 }; btnAddDevices.Click BtnAddDevices_Click; btnClearMarkers new Button { Text 清空所有标记, Location new Point(570, 20), Width 100 }; btnClearMarkers.Click BtnClearMarkers_Click; panelBottom.Controls.Add(lblLng); panelBottom.Controls.Add(txtLng); panelBottom.Controls.Add(lblLat); panelBottom.Controls.Add(txtLat); panelBottom.Controls.Add(btnAddDevices); panelBottom.Controls.Add(btnClearMarkers); this.Controls.Add(panelBottom); this.Text WinForm百度地图CefSharp; this.Size new Size(1000, 700); } #endregion #region CefSharp初始化核心逻辑 private void InitCefSharp() { if (!Cef.IsInitialized) { var settings new CefSettings(); settings.CachePath Path.Combine(AppDomain.CurrentDomain.BaseDirectory, CefCache); Cef.Initialize(settings); } // 创建CefSharp控件 _chromeBrowser new ChromiumWebBrowser() { Dock DockStyle.Fill }; this.Controls.Add(_chromeBrowser); _chromeBrowser.BringToFront(); // 绑定C#对象到JS名称为cefSharpComm对应HTML中的window.cefSharpComm _chromeBrowser.JavascriptObjectRepository.Settings.LegacyBindingEnabled true; _chromeBrowser.JavascriptObjectRepository.Register( cefSharpComm, // JS中访问的对象名 new MapCommunicatorCef((lng, lat) { // 接收地图点击的坐标更新UI this.Invoke(new Action(() { txtLng.Text lng; txtLat.Text lat; MessageBox.Show($你点击了地图\n经度{lng}\n纬度{lat}); })); }), isAsync: true, options: BindingOptions.Default ); // 监听页面加载完成事件 _chromeBrowser.FrameLoadEnd (s, e) { if (e.Frame.IsMain) { this.Invoke(new Action(() MessageBox.Show(地图加载完成))); } }; } private void LoadBaiduMapWithCefSharp() { string htmlPath Path.Combine(AppDomain.CurrentDomain.BaseDirectory, BaiduMap.html); _chromeBrowser.Load(file:/// htmlPath.Replace(\\, /)); } private void BtnAddDevices_Click(object sender, EventArgs e) { try { string devicesJson JsonConvert.SerializeObject(_deviceList); // CefSharp调用JS方法异步 _chromeBrowser.ExecuteScriptAsync($addDeviceMarkers({devicesJson})); MessageBox.Show($成功添加 {_deviceList.Count} 个设备标记); } catch (Exception ex) { MessageBox.Show(添加标记失败 ex.Message); } } private void BtnClearMarkers_Click(object sender, EventArgs e) { _chromeBrowser.ExecuteScriptAsync(clearAllDeviceMarkers()); MessageBox.Show(已清空所有设备标记); } private void InitDeviceData() { _deviceList new ListDeviceModel { new DeviceModel { Id 1, Name 风速计-1, Lng 116.3907, Lat 39.9128 }, new DeviceModel { Id 2, Name 风速计-2, Lng 116.4102, Lat 39.9085 }, new DeviceModel { Id 3, Name 温湿度计-1, Lng 116.4058, Lat 39.9201 }, new DeviceModel { Id 4, Name 气压计-1, Lng 116.3895, Lat 39.9156 } }; } #endregion #region 辅助类 // CefSharp通信类供JS调用 public class MapCommunicatorCef { private readonly Actionstring, string _onMapClicked; public MapCommunicatorCef(Actionstring, string onMapClicked) { _onMapClicked onMapClicked; } // 供JS调用的方法接收经纬度 public void OnMapClicked(string lng, string lat) { _onMapClicked?.Invoke(lng, lat); } } // 设备模型 public class DeviceModel { public int Id { get; set; } public string Name { get; set; } public double Lng { get; set; } public double Lat { get; set; } } #endregion // 释放CefSharp资源 protected override void OnFormClosed(FormClosedEventArgs e) { base.OnFormClosed(e); _chromeBrowser?.Dispose(); Cef.Shutdown(); } } }步骤 4测试运行效果和 WebBrowser 版完全一致但地图加载速度、兼容性更好支持所有百度地图 JS API 特性。关键知识点详解1. 双向通信核心原理方向WebBrowser 实现CefSharp 实现JS→C#window.external.方法名()[ComVisible(true)]类window.绑定名.方法名()JavascriptObjectRepository.Register()C#→JSwebBrowser.Document.InvokeScript(方法名, 参数)chromeBrowser.ExecuteScriptAsync(方法名(参数))2. 新手常见坑WebBrowser 通信失败未加[ComVisible(true)]或 IE 内核版本过低CefSharp 绑定失败未开启LegacyBindingEnabled true或平台目标不是 x64JSON 序列化失败未安装Newtonsoft.Json或设备模型属性名与 JS 不一致地图空白AK 错误或 HTML 中 AK 未替换或网络问题。3. 扩展功能建议动态更新设备位置新增updateDevicePositionJS 方法WinForm 调用该方法传入设备 ID 和新坐标标记自定义样式在 JS 中修改BMapGL.Marker的图标setIcon方法设备状态显示根据设备状态在线 / 离线设置不同颜色的标记坐标持久化将地图点击的坐标保存到本地文件 / 数据库。总结核心要点回顾JS→C#通过绑定通信对象让 JS 调用 C# 的方法传递地图点击坐标C#→JS将 C# 的设备数据序列化为 JSON调用 JS 的批量加标记方法WebBrowser 适合快速入门无依赖CefSharp 适合实际项目兼容性好关键前提百度 AK 有效、JSON 序列化包安装、控件环境配置正确。后续扩展如果需要实现「设备标记拖拽更新坐标」「根据设备 ID 查询定位」「地图测距 / 测面积」等功能只需在 JS 中扩展对应方法再通过 C# 调用即可核心通信逻辑完全复用。