在运行时使用 Xamarin.Forms.Maps 创建折线时如何附加位置?
Posted
技术标签:
【中文标题】在运行时使用 Xamarin.Forms.Maps 创建折线时如何附加位置?【英文标题】:How to append positions when creating a Polyline with Xamarin.Forms.Maps in runtime? 【发布时间】:2021-06-04 03:19:15 【问题描述】:我正在运行时创建Xamarin.Forms.Maps.Polyline
。鉴于Polyline.Geopath
属性是只读的,如何动态附加positions?
在运行时创建折线
按照文档创建折线:Xamarin.Forms Map Polygons and Polylines。此链接是代码中固定位置的教程。如何在运行时动态分配位置。
using Xamarin.Forms.Maps;
// ...
Map map = new Map
// ...
;
创建一个对象来存储路由数据(从json中提取的数据)
public class MapRoute
//[JsonPropertyName("timestamp")]
public long timestamp get; set;
//[JsonPropertyName("lat")]
public double lat get; set;
//[JsonPropertyName("lng")]
public double lng get; set;
public MapRoute(long v1, double v2, double v3)
timestamp = v1;
lat = v2;
lng = v3;
将路由对象序列化为 JsonString。
public void RouteAppend(MapRoute route)
JsonString.Append(JsonSerializer.Serialize(route));
JsonString.Append(",");
在现实生活中,jsonString中有2个以上的元素(jsonString中存储的元素有1000多个)
readonly string jsonString = " [ \"timestamp\": 1514172600000, \"Lat\": 37.33417925, \"Lng\": -122.04153133, " + "\"timestamp\": 1514172610000, \"Lat\": 37.33419725, \"Lng\": -122.04151333 ]";
JsonDocument doc;
JsonElement root;
private IList<Position> pos;
doc = Parse(testString);
root = doc.RootElement;
var routes = root.EnumerateArray();
while (routes.MoveNext())
var user = routes.Current;
pos.Add(new Position(Convert.ToDouble(user.GetProperty("lat")), Convert.ToDouble(user.GetProperty("lng"))));
最后,有一个列表pos
有很多Position
,我会将pos
分配给Geopath
。不幸的是,这是不允许的。它是一个只读属性:
// instantiate a polyline
Polyline polyline = new Polyline
StrokeColor = Color.Blue,
StrokeWidth = 12,
Geopath = pos // It is a readonly property, cannot assign pos to Geopath
// add the polyline to the map's MapElements collection
map.MapElements.Add(polyline);
如何解决这个问题?
【问题讨论】:
【参考方案1】:虽然Polyline.Geopath
是一个get-only 属性,但返回的IList<Position>
不是只读集合,因此您可以在构造后将Position
对象添加到其中。
因此您可以创建以下工厂方法:
public static class PolylineFactory
const string latitudeJsonName = "Lat";
const string longitudeJsonName = "Lng";
public static Polyline FromLatLngJson(string jsonString, float? strokeWidth = default, Color strokeColor = default)
using var doc = JsonDocument.Parse(jsonString);
var query = doc.RootElement.EnumerateArray()
// GetProperty performs property name matching as an ordinal, case-sensitive comparison.
.Select(e => new Position(e.GetProperty(latitudeJsonName).GetDouble(), e.GetProperty(longitudeJsonName).GetDouble()));
var polyline = new Polyline();
if (strokeColor != default)
polyline.StrokeColor = strokeColor;
if (strokeWidth != default)
polyline.StrokeWidth = strokeWidth.Value;
foreach (var position in query)
polyline.Geopath.Add(position);
return polyline;
另外,在 .NET 5 中,JsonSerializer
支持使用单个参数化构造函数反序列化对象,因此如果您稍微修改您的 MapRoute
类,如下所示,您可以将您的 jsonString
反序列化为 List<MapRoute>
直接:
public class MapRoute
public long timestamp get; set;
public double lat get; set;
public double lng get; set;
public MapRoute(long timestamp, double lat, double lng)
// The constructor argument names and property names must match for JsonSerializer to bind to the constructor successfully
this.timestamp = timestamp;
this.lat = lat;
this.lng = lng;
public static class PolylineFactory
public static Polyline FromLatLngJson(string jsonString, float? strokeWidth = default, Color strokeColor = default)
var routes = JsonSerializer.Deserialize<List<MapRoute>>(jsonString, new JsonSerializerOptions PropertyNameCaseInsensitive = true );
var polyline = new Polyline();
if (strokeColor != default)
polyline.StrokeColor = strokeColor;
if (strokeWidth != default)
polyline.StrokeWidth = strokeWidth.Value;
foreach (var route in routes)
polyline.Geopath.Add(new Position(route.lat, route.lng));
return polyline;
(在 .NET Core 3.x 中,您需要向 MapRoute
添加无参数构造函数,并确保所有属性都是可变的才能成功反序列化。)
无论哪种方式,都可以如下调用工厂方法:
var polyline = PolylineFactory.FromLatLngJson(jsonString, 12, Color.Blue);
注意事项:
JsonElement.GetProperty()
执行属性名称匹配作为一个序数、区分大小写的比较,因此您需要传递"Lat"
和"Lng"
而不是"lat"
和"lng"
,因为您的jsonString
是帕斯卡大小写而不是骆驼大小写。
如果这是您问题中的错误,并且您的 JSON 字符串确实是驼峰式大小写,请适当修改 latitudeJsonName
和 longitudeJsonName
。
如果您在获取属性时需要忽略大小写,请参阅Ignore case when using TryGetProperty。
Convert.ToDouble()
通过使用当前线程文化的格式约定来解释传入的值。在许多欧洲语言环境中,,
逗号在格式化浮点值时用作小数分隔符。由于这与 JSON 标准不一致,因此最好使用内置方法 JsonElement.GetDouble()
,它将始终使用正确的小数分隔符。
JsonDocument
是一次性的:
此类利用池化内存中的资源来最大程度地减少垃圾收集器 (GC) 在高使用情况下的影响。未能正确处置此对象将导致内存未返回到池中,这将增加对框架各个部分的 GC 影响。
在您的代码中,您不会处理您的doc
,但您应该处理。
演示小提琴#1 here 使用JsonDocument
,#2 here 使用MapRoute
。
【讨论】:
感谢您的帮助,我会尽快采纳您的建议 采纳了您的建议,问题已解决。谢谢。以上是关于在运行时使用 Xamarin.Forms.Maps 创建折线时如何附加位置?的主要内容,如果未能解决你的问题,请参考以下文章
如何在单击 xamarin.forms.maps iOS c# 时更改 pin 图标
在 iOS 上的 Xamarin.Forms.Maps 中使用 Xamarin.Essentials Geolocation 获取设备位置的奇怪问题
Xamarin.Forms.Maps 如何像谷歌地图一样在图钉旁边/上方有一个标签?