Xamarin Forms Maps - 如何刷新/更新地图 - CustomMap Renderer

Emi*_*m23 3 maps refresh updates xamarin xamarin.forms

如果您正在搜索完整的折线,引脚,图块,UIOptions(以及即将推出的3D效果)渲染/实现,您应该在我在XamarinByEmixam23 /..../ Map上制作的公共github上获取战利品.


我搜索了很多,但我仍然有同样的问题:

如何更新,刷新或重新加载Xamarin.Forms.Maps?

在类定义(类CustomMap:Map)中,没有更新映射的方法.也许MVVM逻辑可以解决问题,但我无法在Web上找到它.

我按照本教程了解地图:使用地图

为了自定义它,我遵循了本教程:在地图上突出显示路线

所以,经过这些教程(我做了同样的事情,没有变化),我尝试了2个RouteCoordinates给了我一条直线......然后我做了一个完美的算法.

DirectionMap

public class DirectionMap
{
    public Distance distance { get; set; }
    public Duration duration { get; set; }
    public Address address_start { get; set; }
    public Address address_end { get; set; }
    public List<Step> steps { get; set; }

    public class Distance
    {
        public string text { get; set; }
        public int value { get; set; }
    }
    public class Duration
    {
        public string text { get; set; }
        public int value { get; set; }
    }
    public class Address
    {
        public string text { get; set; }
        public Position position { get; set; }
    }
    public class Step
    {
        public Position start { get; set; }
        public Position end { get; set; }
    }
}
Run Code Online (Sandbox Code Playgroud)

ResponseHttpParser

public static void parseDirectionGoogleMapsResponse(HttpStatusCode httpStatusCode, JObject json, Action<DirectionMap, string> callback)
{
    switch (httpStatusCode)
    {
        case HttpStatusCode.OK:

            DirectionMap directionMap = null;
            string strException = null;

            try
            {
                directionMap = new DirectionMap()
                {
                    distance = new DirectionMap.Distance()
                    {
                        text = (json["routes"][0]["legs"][0]["distance"]["text"]).ToString(),
                        value = Int32.Parse((json["routes"][0]["legs"][0]["distance"]["value"]).ToString())
                    },
                    duration = new DirectionMap.Duration()
                    {
                        text = (json["routes"][0]["legs"][0]["duration"]["text"]).ToString(),
                        value = Int32.Parse((json["routes"][0]["legs"][0]["duration"]["value"]).ToString())
                    },
                    address_start = new DirectionMap.Address()
                    {
                        text = (json["routes"][0]["legs"][0]["start_address"]).ToString(),
                        position = new Position(Double.Parse((json["routes"][0]["legs"][0]["start_location"]["lat"]).ToString()), Double.Parse((json["routes"][0]["legs"][0]["start_location"]["lng"]).ToString()))
                    },
                    address_end = new DirectionMap.Address()
                    {
                        text = (json["routes"][0]["legs"][0]["end_address"]).ToString(),
                        position = new Position(Double.Parse((json["routes"][0]["legs"][0]["end_location"]["lat"]).ToString()), Double.Parse((json["routes"][0]["legs"][0]["end_location"]["lng"]).ToString()))
                    }
                };

                bool finished = false;
                directionMap.steps = new List<Step>();
                int index = 0;

                while (!finished)
                {
                    try
                    {
                        Step step = new Step()
                        {
                            start = new Position(Double.Parse((json["routes"][0]["legs"][0]["steps"][index]["start_location"]["lat"]).ToString()), Double.Parse((json["routes"][0]["legs"][0]["steps"][index]["start_location"]["lng"]).ToString())),
                            end = new Position(Double.Parse((json["routes"][0]["legs"][0]["steps"][index]["end_location"]["lat"]).ToString()), Double.Parse((json["routes"][0]["legs"][0]["steps"][index]["end_location"]["lng"]).ToString()))
                        };
                        directionMap.steps.Add(step);
                        index++;
                    }
                    catch (Exception e)
                    {
                        finished = true;
                    }
                }
            }
            catch (Exception e)
            {
                directionMap = null;
                strException = e.ToString();
            }
            finally
            {
                callback(directionMap, strException);
            }
            break;
        default:
            switch (httpStatusCode)
            {

            }
            callback(null, json.ToString());
            break;
    }
}
Run Code Online (Sandbox Code Playgroud)

我得到一些私人计算的距离和持续时间,并得到我放入List <>的每一步;

当一切都完成后,我使用我的回调将我们带回控制器(MapPage.xaml.cs,XAML表单页面(Xamarin Portable))

现在,一切都变得奇怪了.这就像地图没有得到改变

public partial class MapPage : ContentPage
{
    public MapPage()
    {
        InitializeComponent();
        setupMap();
        setupMapCustom();
    }

    public void setupMapCustom()
    {
        customMap.RouteCoordinates.Add(new Position(37.785559, -122.396728));
        customMap.RouteCoordinates.Add(new Position(37.780624, -122.390541));
        customMap.RouteCoordinates.Add(new Position(37.777113, -122.394983));
        customMap.RouteCoordinates.Add(new Position(37.776831, -122.394627));

        customMap.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(37.79752, -122.40183), Xamarin.Forms.Maps.Distance.FromMiles(1.0)));
    }       

    public async void setupMap()
    {
        customMap.MapType = MapType.Satellite;

        string origin = "72100 Le Mans";
        string destination = "75000 Paris";

        HttpRequest.getDirections(origin, destination, callbackDirections);

        customMap.RouteCoordinates.Add(await MapUtilities.GetMapPointOfStreetAddress(origin));
        Position position = await MapUtilities.GetMapPointOfStreetAddress(destination);
        //customMap.RouteCoordinates.Add(position);

        var pin = new Pin
        {
            Type = PinType.Place,
            Position = position,
            Label = "Destination !!",
        };
        customMap.Pins.Add(pin);
    }

    private async void callbackDirections(Object obj, string str)
    {
        if (obj != null)
        {
            DirectionMap directionMap = obj as DirectionMap;

            foreach (Step step in directionMap.steps)
            {
                customMap.RouteCoordinates.Add(step.start);
                System.Diagnostics.Debug.WriteLine("add step");
            }

            customMap.RouteCoordinates.Add(directionMap.address_end.position);
            System.Diagnostics.Debug.WriteLine("add last step");
        }
        else
        {
            System.Diagnostics.Debug.WriteLine(str);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我运行我的应用程序,一切正常,直到它快速,因为我的算法花费的时间等,回调来得太晚,然后我需要刷新,重新加载或更新我的地图......无论如何,我需要更新我的未来的地图,所以...如果有人可以提供帮助,欢迎这一个!

编辑1 我看了你的答案(非常感谢!;))但它不起作用:/

我像你一样更新了CustomMap

public class CustomMap : Map
{
    public static readonly BindableProperty RouteCoordinatesProperty =
    BindableProperty.Create<CustomMap, List<Position>>(p => p.RouteCoordinates, new List<Position>());

    public List<Position> RouteCoordinates
    {
        get { return (List<Position>)GetValue(RouteCoordinatesProperty); }
        set { SetValue(RouteCoordinatesProperty, value); }
    }

    public CustomMap()
    {
        RouteCoordinates = new List<Position>();
    }
}
Run Code Online (Sandbox Code Playgroud)

同为CustomMapRenderer(Droid的)

public class CustomMapRenderer : MapRenderer, IOnMapReadyCallback
{
    GoogleMap map;
    Polyline polyline;

    protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<Xamarin.Forms.View> e)
    {
        base.OnElementChanged(e);

        if (e.OldElement != null)
        {
            // Unsubscribe
        }

        if (e.NewElement != null)
        {
            ((MapView)Control).GetMapAsync(this);
        }
    }

    protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        base.OnElementPropertyChanged(sender, e);
        if (this.Element == null || this.Control == null)
            return;

        if (e.PropertyName == CustomMap.RouteCoordinatesProperty.PropertyName)
        {
            UpdatePolyLine();
        }
    }

    private void UpdatePolyLine()
    {
        if (polyline != null)
        {
            polyline.Remove();
            polyline.Dispose();
        }

        var polylineOptions = new PolylineOptions();
        polylineOptions.InvokeColor(0x66FF0000);

        foreach (var position in ((CustomMap)this.Element).RouteCoordinates)
        {
            polylineOptions.Add(new LatLng(position.Latitude, position.Longitude));
        }

        polyline = map.AddPolyline(polylineOptions);
    }

    public void OnMapReady(GoogleMap googleMap)
    {
        map = googleMap;
        UpdatePolyLine();
    }
}
Run Code Online (Sandbox Code Playgroud)

所以,对于最后一次更改,在我的MapPage.xaml.cs中,我在callbackDirections中进行了更改,如您所解释的那样(我希望我做得很好)

private async void callbackDirections(Object obj, string str)
    {
        if (obj != null)
        {
            Device.BeginInvokeOnMainThread(() =>
            {
                DirectionMap directionMap = obj as DirectionMap;
                var list = new List<Position>(customMap.RouteCoordinates);

                foreach (Step step in directionMap.steps)
                {
                    list.Add(directionMap.address_end.position);
                    System.Diagnostics.Debug.WriteLine("add step");
                }

                System.Diagnostics.Debug.WriteLine("last step");
                customMap.RouteCoordinates = list;
                System.Diagnostics.Debug.WriteLine("finished?");
            });
        }
        else
        {
            System.Diagnostics.Debug.WriteLine(str);
        }
    }
Run Code Online (Sandbox Code Playgroud)

地图仍然不显示折线:/我只进行了这些更改,我没有更改我以前的代码中的任何其他内容.

我没有告诉你,但我不是MVVM绑定的专家,所以如果我忘记了什么,我很抱歉:/

编辑2 因此,在您的答案和阅读,阅读并重新阅读您的答案之后,MapPage.xaml.cs中有我的"测试代码"

public MapPage()
    {
        InitializeComponent();
        //HttpRequest.getDirections(origin, destination, callbackDirections);

        Device.BeginInvokeOnMainThread(() =>
        {
            customMap.RouteCoordinates = new List<Position>
            {
                new Position (37.797534, -122.401827),
                new Position (37.776831, -122.394627)
            };
        });

        //setupMap();
        //setupMapCustom();
    }
Run Code Online (Sandbox Code Playgroud)

因为它不起作用(对我来说),我看了看我的代码,然后,我看到它public static readonly BindableProperty RouteCoordinatesProperty = BindableProperty.Create<CustomMap, List<Position>>( p => p.RouteCoordinates, new List<Position>());被弃用了..

所以我在这篇文章上用不同的方式来实现这个绑定,但它也说这种方式已被弃用了.请看这里 ...我还看到一些关于绑定的教程,说他们把一些代码放到他们的xaml中,让我记住你矿

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
     xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
     xmlns:local="clr-namespace:NAMESPACE;assembly=NAMESPACE"
     x:Class="NAMESPACE.Controlers.MapPage">
         <ContentPage.Content>
             <local:CustomMap x:Name="customMap"/>
         </ContentPage.Content>
</ContentPage>
Run Code Online (Sandbox Code Playgroud)

我没有使用ItemSource ="{PolylineBindable}"

Sve*_*übe 8

示例中的自定义渲染器不用于动态更新路径.它只是针对这种情况实现的,其中在初始化地图/第一次绘制路径之前已知路径的所有点.因此,您遇到了这种竞争条件,因为您正在从Web服务加载指示.

所以你必须做一些改变:

RouteCoordinates必须是BindableProperty

public class CustomMap : Map
{
    public static readonly BindableProperty RouteCoordinatesProperty =
        BindableProperty.Create<CustomMap, List<Position>>(p => p.RouteCoordinates, new List<Position>());

    public List<Position> RouteCoordinates
    {
        get { return (List<Position>)GetValue(RouteCoordinatesProperty); }
        set { SetValue(RouteCoordinatesProperty, value); }
    }

    public CustomMap ()
    {
        RouteCoordinates = new List<Position>();
    }
}
Run Code Online (Sandbox Code Playgroud)

每当坐标改变时更新折线

  • 将折线的创建从中移动OnMapReadyUpdatePolyLine
  • 打电话UpdatePolyLineOnMapReadyOnElementPropertyChanged
public class CustomMapRenderer : MapRenderer, IOnMapReadyCallback
{
    GoogleMap map;
    Polyline polyline;

    protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<View> e)
    {
        base.OnElementChanged(e);

        if (e.OldElement != null)
        {
            // Unsubscribe
        }

        if (e.NewElement != null)
        {
            ((MapView)Control).GetMapAsync(this);
        }
    }

    protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        base.OnElementPropertyChanged(sender, e);
        if (this.Element == null || this.Control == null)
            return;

        if (e.PropertyName == CustomMap.RouteCoordinatesProperty.PropertyName)
        {
            UpdatePolyLine();
        }
    }

    private void UpdatePolyLine()
    {
        if (polyline != null)
        {
            polyline.Remove();
            polyline.Dispose();
        }               

        var polylineOptions = new PolylineOptions();
        polylineOptions.InvokeColor(0x66FF0000);

        foreach (var position in ((CustomMap)this.Element).RouteCoordinates)
        {
            polylineOptions.Add(new LatLng(position.Latitude, position.Longitude));
        }

        polyline = map.AddPolyline(polylineOptions);
    }

    public void OnMapReady(GoogleMap googleMap)
    {
        map = googleMap;
        UpdatePolyLine();
    }
}
Run Code Online (Sandbox Code Playgroud)

设置数据

更新位置会有所改变.您必须(创建新列表)并将其设置为,而不是将位置添加到现有列表RouteCoordinates.您可以使用Device.BeginInvokeOnMainThread以确保在UI线程上执行操作.否则折线不会更新.

Device.BeginInvokeOnMainThread(() =>
{
    customMap.RouteCoordinates = new List<Position>
    {
        new Position (37.797534, -122.401827),
        new Position (37.776831, -122.394627)
    };
}) 
Run Code Online (Sandbox Code Playgroud)

在你的情况下它是这样的

var list = new List<Position>(customMap.RouteCoordinates);
list.Add(directionMap.address_end.position);
customMap.RouteCoordinates = list;
Run Code Online (Sandbox Code Playgroud)

去做

在iOS上,你现在要实现类似的行为(如UpdatePolyLine)

注意

这可能不是最高性能的实现,因为您重绘所有内容而不是添加一个点.只要你没有性能问题就可以了:)


Emi*_*m23 0

因此,经过大量搜索,当然还有@Sven-Michael St\xc3\xbcbe 的答案,您可以获得适用于每个平台“Android、iOS、WinPhone”的正确地图。按照我的代码,然后按照 @Sven-Michael St\xc3\xbcbe\ 的答案进行编辑。

\n\n

一旦你完成了所有的事情,它就可以工作(就像@Sven-Michael St\xc3\xbcbe),但它也无法工作(就像我一样)。如果不起作用,请尝试更改以下代码:

\n\n
public static readonly BindableProperty RouteCoordinatesProperty =\n    BindableProperty.Create<CustomMap, List<Position>>(\n        p => p.RouteCoordinates, new List<Position>());\n
Run Code Online (Sandbox Code Playgroud)\n\n

经过

\n\n
public static readonly BindableProperty RouteCoordinatesProperty =\n    BindableProperty.Create(nameof(RouteCoordinates), typeof(List<Position>), typeof(CustomMap), new List<Position>(), BindingMode.TwoWay);\n
Run Code Online (Sandbox Code Playgroud)\n\n

有关它的更多信息,请参阅文档。(已弃用的实施)

\n\n

然后代码就可以工作了!

\n\n

PS:最后的折线可能会遇到一些问题,它没有沿着正确的道路行驶,我正在解决它。

\n\n

PS2:我还将制作一个视频来解释如何编写自定义地图,以便不必安装 NuGet 包,以便能够在最后编辑所有内容!(第一个是法语,第二个是英语,这篇文章将在制作视频时编辑)

\n\n

再次感谢@Sven-Michael St\xc3\xbcbe!也感谢他的回答:)

\n