如何通过API更新Xamarin iOS谷歌地图自定义PIN上的信息
Xamarin iOS 谷歌地图自定义Pin更新问题解决
问题根因
- 空引用异常:你在
Task.Run开启的后台线程中直接操作customMap.Pins等UI控件,Xamarin要求所有UI相关操作必须在主线程执行,后台线程操作UI会导致控件状态异常,触发空引用错误。 - InfoBox不更新:
CustomPin类未实现INotifyPropertyChanged接口,属性值修改后无法通知UI自动刷新,所以即使字段值修改成功,界面展示的信息也不会同步更新。
修复步骤
方案1(推荐:无需清空重加Pin)
让CustomPin实现属性变更通知接口,修改属性后自动触发UI刷新:
using System.ComponentModel; using System.Runtime.CompilerServices; using Xamarin.Forms.Maps; public class CustomPin : Pin, INotifyPropertyChanged { private int _alertLevel; private int _codeNum; private int _mapCode; public int AlertLevel { get => _alertLevel; set { _alertLevel = value; OnPropertyChanged(); // 如果InfoBox展示内容依赖AlertLevel/CodeNum/MapCode拼接,同步触发关联属性的变更通知 OnPropertyChanged(nameof(Label)); OnPropertyChanged(nameof(Address)); } } public int CodeNum { get => _codeNum; set { _codeNum = value; OnPropertyChanged(); OnPropertyChanged(nameof(Label)); } } public int MapCode { get => _mapCode; set { _mapCode = value; OnPropertyChanged(); OnPropertyChanged(nameof(Address)); } } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
修改APIConnection方法,增加非空判断和属性更新逻辑:
public async Task APIConnection(List<CustomPin> pins) { WaterBindingData waterData = await _restServiceData.GetWaterDataForecast( GenerateRequestUri(Constants.EndPoint), GenerateRequestUriStations(Constants.EndPoint)); // 增加非空判断避免空引用 if(waterData?.WaterStation?.Stations == null) return; foreach (var water in waterData.WaterStation.Stations) { int codeNum = water.CodeNum; int level = water.AlertLevelStation; int mapcode = water.MapCode; foreach (var item in pins) { if (item.CodeNum == water.CodeNum) { // 直接更新属性,自动触发UI刷新 item.AlertLevel = level; item.CodeNum = codeNum; item.MapCode = mapcode; // 如果Label/Address是固定文本,直接在这里修改值即可 // item.Label = $"站点{codeNum} 预警等级{level}"; // item.Address = $"地图编码{mapcode}"; } } } }
修改API调用代码,去掉不必要的Task.Run:
// 原代码:Task.Run(async () => await APIConnection(customMap.CustomPins)); // 替换为,避免额外线程开销 _ = APIConnection(customMap.CustomPins); // 如果当前上下文是异步方法,直接await调用即可 // await APIConnection(customMap.CustomPins);
方案2(坚持清空重加Pin)
如果需要强制刷新所有Pin,把UI操作调度到主线程执行:
public async Task APIConnection(List<CustomPin> pins) { WaterBindingData waterData = await _restServiceData.GetWaterDataForecast( GenerateRequestUri(Constants.EndPoint), GenerateRequestUriStations(Constants.EndPoint)); if(waterData?.WaterStation?.Stations == null) return; foreach (var water in waterData.WaterStation.Stations) { int codeNum = water.CodeNum; int level = water.AlertLevelStation; int mapcode = water.MapCode; foreach (var item in pins) { if (item.CodeNum == water.CodeNum) { item.AlertLevel = level; item.CodeNum = codeNum; item.MapCode = mapcode; item.Label = $"更新后的Label内容"; item.Address = $"更新后的Address内容"; } } } // UI操作必须放到主线程执行 Device.BeginInvokeOnMainThread(() => { customMap.Pins.Clear(); foreach(var item in pins) { customMap.Pins.Add(item); } // 同步更新CustomPins集合,避免自定义渲染器逻辑异常 customMap.CustomPins = new List<CustomPin>(pins); }); }
内容的提问来源于stack exchange,提问作者Blagovest Pizhev
相关产品推荐
相关产品推荐

