c# - 如何修复.Exception:'未找到特定引脚的自定义引脚
问题描述
请帮我解决这个问题。 我正在使用这篇文章在 xamarin 中制作自定义渲染器: Xamarin Form Custom Renderer
一切正常,直到我将 pin 信息转换为 JSON 文件。
所以基本上现在LAT、LNG、标签、名称和 URL 都存储在JSON 文件而不是 C# 文件中。为了测试,我做了 3 个临时别针。但其中只有 1 个显示自定义呈现的窗口。当我单击其他 2 个引脚时,会发生异常,因为未找到自定义引脚。但是为最后一个引脚找到了自定义引脚,但不是第一个和第二个引脚,这让我感到困惑。
我的代码:
JSON文件:
[
{"Label" :"Country1",
"Address":"A multine paragraph",
"Lat":"-12",
"Lng":"14",
"Name":"Xamarin",
"Url": "http://xamarin.com/about/"
},
{ "Label" :"Country2",
"Address":"Multiline paragraph",
"Lat":"-25",
"Lng":"45",
"Name":"Xamarin",
"Url": "http://xamarin.com/about/"
},
{ "Label" :"Country3",
"Address":"Multiline paragraph",
"Lat":"-5",
"Lng":"45",
"Name":"Xamarin",
"Url": "http://xamarin.com/about/"
}
]
MapPage.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Maps;
using Newtonsoft.Json;
using System.IO;
using Xamarin.Forms.Xaml;
using System.Reflection;
namespace Orbage
{
public partial class MapPage : ContentPage
{
public MapPage()
{
CustomMap customMap = new CustomMap
{
MapType = MapType.Hybrid
};
Content = customMap;
var assembly = IntrospectionExtensions.GetTypeInfo(typeof(MapPage)).Assembly;
Stream stream = assembly.GetManifestResourceStream("Orbage.Mydata.json");
string json = "";
using (var reader = new System.IO.StreamReader(stream))
{
json = reader.ReadToEnd();
}
var places = JsonConvert.DeserializeObject<List<Mydata>>(json);
List<CustomPin> custompinList = new List<CustomPin>();
foreach (var place in places)
{
CustomPin pin = new CustomPin
{
Type = PinType.Place,
Position = new Position(Double.Parse(place.Lat), Double.Parse(place.Lng)),
Label = place.Label,
Address = place.Address,
Name = place.Name,
Url = place.Url
};
customMap.Pins.Add(pin);
customMap.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(37.79752, -122.40183), Distance.FromMiles(1.0)));
customMap.CustomPins = custompinList;
}
}
}
public class Mydata
{
public string Label { get; set; }
public string Address { get; set; }
public string Lat { get; set; }
public string Lng { get; set; }
public string Name { get; set; }
public string Url { get; set; }
}
}
自定义引脚:
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms.Maps;
namespace Orbage
{
public class CustomPin : Pin
{
public string Name { get; set; }
public string Url { get; set; }
public string Adress { get; set; }
public string Lat { get; set; }
public string Lng { get; set; }
}
}
自定义地图:
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms.Maps;
namespace Orbage
{
public class CustomMap : Map
{
public List<CustomPin> CustomPins { get; set; }
}
}
CustomMapRenderer.cs:
using System;
using System.Collections.Generic;
using Android.Content;
using Android.Gms.Maps;
using Android.Gms.Maps.Model;
using Android.Widget;
using ----;
using ----.Droid;
using Xamarin.Forms;
using Xamarin.Forms.Maps;
using Xamarin.Forms.Maps.Android;
[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace ----.Droid
{
public class CustomMapRenderer : MapRenderer, GoogleMap.IInfoWindowAdapter
{
List<CustomPin> customPins;
public CustomMapRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<Map> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
NativeMap.InfoWindowClick -= OnInfoWindowClick;
}
if (e.NewElement != null)
{
var formsMap = (CustomMap)e.NewElement;
customPins = formsMap.CustomPins;
}
}
protected override void OnMapReady(GoogleMap map)
{
base.OnMapReady(map);
NativeMap.InfoWindowClick += OnInfoWindowClick;
NativeMap.SetInfoWindowAdapter(this);
}
protected override MarkerOptions CreateMarker(Pin pin)
{
var marker = new MarkerOptions();
marker.SetPosition(new LatLng(pin.Position.Latitude, pin.Position.Longitude));
marker.SetTitle(pin.Label);
marker.SetSnippet(pin.Address);
marker.SetIcon(BitmapDescriptorFactory.FromResource(Resource.Drawable.pin));
return marker;
}
void OnInfoWindowClick(object sender, GoogleMap.InfoWindowClickEventArgs e)
{
var customPin = GetCustomPin(e.Marker);
if (customPin == null)
{
throw new Exception("Custom pin not found");
}
if (!string.IsNullOrWhiteSpace(customPin.Url))
{
var url = Android.Net.Uri.Parse(customPin.Url);
var intent = new Intent(Intent.ActionView, url);
intent.AddFlags(ActivityFlags.NewTask);
Android.App.Application.Context.StartActivity(intent);
}
}
public Android.Views.View GetInfoContents(Marker marker)
{
var inflater = Android.App.Application.Context.GetSystemService(Context.LayoutInflaterService) as Android.Views.LayoutInflater;
if (inflater != null)
{
Android.Views.View view;
var customPin = GetCustomPin(marker);
if (customPin == null)
{
throw new Exception("Custom pin not found");
}
if (customPin.Name.Equals("Xamarin"))
{
view = inflater.Inflate(Resource.Layout.XamarinMapInfoWindow, null);
}
else
{
view = inflater.Inflate(Resource.Layout.MapInfoWindow, null);
}
var infoTitle = view.FindViewById<TextView>(Resource.Id.InfoWindowTitle);
var infoSubtitle = view.FindViewById<TextView>(Resource.Id.InfoWindowSubtitle);
if (infoTitle != null)
{
infoTitle.Text = marker.Title;
}
if (infoSubtitle != null)
{
infoSubtitle.Text = marker.Snippet;
}
return view;
}
return null;
}
public Android.Views.View GetInfoWindow(Marker marker)
{
return null;
}
CustomPin GetCustomPin(Marker annotation)
{
var position = new Position(annotation.Position.Latitude, annotation.Position.Longitude);
foreach (var pin in customPins)
{
if (pin.Position == position)
{
return pin;
}
}
return null;
}
}
}
感谢您看到这一点,我希望这个问题得到解答,并且有相同错误的人得到修复。:)
解决方案
foreach (var place in places)
{
CustomPin pin = new CustomPin
{
Type = PinType.Place,
Position = new Position(Double.Parse(place.Lat), Double.Parse(place.Lng)),
Label = place.Label,
Address = place.Address,
Name = place.Name,
Url = place.Url
};
customMap.CustomPins = new List<CustomPin> { pin }; //this will cause your customMap.CustomPins always has only the last custompin.
customMap.Pins.Add(pin);
customMap.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(37.79752, -122.40183), Distance.FromMiles(1.0)));
}
问题就在这里,你在循环中添加 customMap.CustomPins,所以它总是只有第三个 CustomPin。
尝试将其移出 foreach
:
List<CustomPin> custompinList = new List<CustomPin>();
foreach (var place in places)
{
CustomPin pin = new CustomPin
{
Type = PinType.Place,
Position = new Position(Double.Parse(place.Lat), Double.Parse(place.Lng)),
Label = place.Label,
Address = place.Address,
Name = place.Name,
Url = place.Url
};
custompinList.Add(pin);
customMap.Pins.Add(pin);
customMap.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(37.79752, -122.40183), Distance.FromMiles(1.0)));
}
customMap.CustomPins = custompinList;
更新效果如下:
推荐阅读
- math - 如何为以下匹配问题编写最有效的代码?
- excel - 如果有任何失败,如何显示所有失败,如果没有,则显示没有失败框
- reactjs - React/React Hooks:输入时出现未知的道具类型错误,无法弄清楚如何解决
- python - 如何在给定时间记录和保存用户可编辑的 Django 模型实例
- javascript - 将 HTML 输出解析为本地文件?
- reactjs - How to fix my useEffect or firestore functions to render the profile in the table
- google-analytics - 为什么推迟开始日期会导致 Google Analytics(分析)报告查询返回 0 个结果?
- node.js - 如何在客户端中获取流星异步方法的结果
- python - Git bash(Windows 10):如何在没有“python -m”的情况下调用python脚本开始输入行
- ajax - 来自 laravel 会话登录的经过身份验证的 api 调用。可能吗?