【问题标题】:Xamarin C# - Object in List<> auto update themselves, how to update the list from them?Xamarin C# - List<> 中的对象自动更新自己,如何从它们更新列表?
【发布时间】:2016-11-19 10:41:19
【问题描述】:

我正在为 my Github repository 开发 xamarin 解决方案。对于Pins project,我遇到了问题。事情是这样的,如果您创建一个图钉(又名CustomPin()),然后您想编辑该位置。然后地址名称将更改,如果您更改地址,位置将相同,位置将基于地址名称创建。所以从这里开始,很容易。

但是,当 Pin 地址/位置发生变化时,我希望自己的地图更新。但是因为 List 属性没有改变,所以它不会更新地图。

那么,获取指向父列表或地图的指针?

但是这个解决方案似乎不太适合我的使用,我认为也许存在另一个最佳解决方案,但我不知道该怎么做..

你可以编译项目,但是有三个更新。

自定义密码

public class CustomPin : BindableObject
{
    public static readonly BindableProperty AddressProperty =
        BindableProperty.Create(nameof(Address), typeof(string), typeof(CustomPin), "",
            propertyChanged: OnAddressPropertyChanged);
    public string Address
    {
        get { return (string)GetValue(AddressProperty); }
        set { SetValue(AddressProperty, value); }
    }
    private static async void OnAddressPropertyChanged(BindableObject bindable, object oldValue, object newValue)
    {
        (bindable as CustomPin).SetValue(LocationProperty, await CustomMap.GetAddressPosition(newValue as string));

    }

    public static readonly BindableProperty LocationProperty =
      BindableProperty.Create(nameof(Location), typeof(Position), typeof(CustomPin), new Position(),
          propertyChanged: OnLocationPropertyChanged);
    public Position Location
    {
        get { return (Position)GetValue(LocationProperty); }
        set { SetValue(LocationProperty, value); }
    }
    private static async void OnLocationPropertyChanged(BindableObject bindable, object oldValue, object newValue)
    {
        (bindable as CustomPin).SetValue(AddressProperty, await CustomMap.GetAddressName((Position)newValue));
        Debug.WriteLine("private static async void OnLocationPropertyChanged(BindableObject bindable, object oldValue, object newValue)");
    }

    public string Name { get; set; }
    public string Details { get; set; }
    public string ImagePath { get; set; }
    public uint PinSize { get; set; }
    public uint PinZoomVisibilityMinimumLimit { get; set; }
    public uint PinZoomVisibilityMaximumLimit { get; set; }
    public Point AnchorPoint { get; set; }
    public Action<CustomPin> PinClickedCallback { get; set; }

    public CustomPin(Position location)
    {
        Location = location;
        Name = "";
        Details = "";
        ImagePath = "";
        PinSize = 50;
        PinZoomVisibilityMinimumLimit = uint.MinValue;
        PinZoomVisibilityMaximumLimit = uint.MaxValue;
        AnchorPoint = new Point(0.5, 1);
        PinClickedCallback = null;
    }
    public CustomPin(string address)
    {
        Address = address;
        Name = "";
        Details = "";
        ImagePath = "";
        PinSize = 50;
        PinZoomVisibilityMinimumLimit = uint.MinValue;
        PinZoomVisibilityMaximumLimit = uint.MaxValue;
        AnchorPoint = new Point(0.5, 1);
        PinClickedCallback = null;
    }
    public CustomPin()
    {
        Address = "";
        Location = new Position();

        Name = "";
        Details = "";
        ImagePath = "";
        PinSize = 50;
        PinZoomVisibilityMinimumLimit = uint.MinValue;
        PinZoomVisibilityMaximumLimit = uint.MaxValue;
        AnchorPoint = new Point(0.5, 1);
        PinClickedCallback = null;
    }
}

自定义地图 | PS:只要加上这三个方法

    #region
    public async static Task<string> GetAddressName(Position position)
    {
        string url = "https://maps.googleapis.com/maps/api/geocode/json";
        string additionnal_URL = "?latlng=" + position.Latitude + "," + position.Longitude
        + "&key=" + App.GOOGLE_MAP_API_KEY;

        JObject obj = await CustomMap.GoogleAPIHttpRequest(url, additionnal_URL);

        string address_name;
        try
        {
            address_name = (obj["results"][0]["formatted_address"]).ToString();
        }
        catch (Exception)
        {
            return ("");
        }
        return (address_name);
    }
    public async static Task<Position> GetAddressPosition(string name)
    {
        string url = "https://maps.googleapis.com/maps/api/geocode/json";
        string additionnal_URL = "?address=" + name
        + "&key=" + App.GOOGLE_MAP_API_KEY;

        JObject obj = await CustomMap.GoogleAPIHttpRequest(url, additionnal_URL);

        Position position;
        try
        {
            position = new Position(Double.Parse((obj["results"][0]["geometry"]["location"]["lat"]).ToString()),
                                    Double.Parse((obj["results"][0]["geometry"]["location"]["lng"]).ToString()));
        }
        catch (Exception)
        {
            position = new Position();
        }
        return (position);
    }

    private static async Task<JObject> GoogleAPIHttpRequest(string url, string additionnal_URL)
    {
        try
        {
            var client = new HttpClient();
            client.BaseAddress = new Uri(url);

            var content = new StringContent("{}", Encoding.UTF8, "application/json");
            HttpResponseMessage response = null;
            try
            {
                response = await client.PostAsync(additionnal_URL, content);
            }
            catch (Exception)
            {
                return (null);
            }
            string result = await response.Content.ReadAsStringAsync();
            if (result != null)
            {
                try
                {
                    return JObject.Parse(result);
                }
                catch (Exception)
                {
                    return (null);
                }
            }
            else
            {
                return (null);
            }
        }
        catch (Exception)
        {
            return (null);
        }
    }
    #endregion

MainPage.xaml.cs | PS:PCL 部分,只需更改 Constructor

    public MainPage()
    {
        base.BindingContext = this;

        CustomPins = new List<CustomPin>()
        {
            new CustomPin("Long Beach") { Name = "Le Mans", Details = "Famous city for race driver !", ImagePath = "CustomIconImage.png", PinZoomVisibilityMinimumLimit = 0, PinZoomVisibilityMaximumLimit = 150, PinSize = 75},
           new CustomPin() { Name = "Ruaudin", Details = "Where I'm coming from.", ImagePath = "CustomIconImage.png", PinZoomVisibilityMinimumLimit = 75, PinSize = 65 },
            new CustomPin() { Name = "Chelles", Details = "Someone there.", ImagePath = "CustomIconImage.png", PinZoomVisibilityMinimumLimit = 50, PinSize = 70 },
            new CustomPin() { Name = "Lille", Details = "Le nord..", ImagePath = "CustomIconImage.png", PinZoomVisibilityMinimumLimit = 44, PinSize = 40 },
            new CustomPin() { Name = "Limoges", Details = "I have been there ! :o", ImagePath = "CustomIconImage.png", PinZoomVisibilityMinimumLimit = 65, PinSize = 20 },
            new CustomPin() { Name = "Douarnenez", Details = "A trip..", ImagePath = "CustomIconImage.png", PinZoomVisibilityMinimumLimit = 110, PinSize = 50 }
        };

        Debug.WriteLine("Initialization done.");

        PinActionClicked = PinClickedCallback;

        PinsSize = Convert.ToUInt32(100);

        MinValue = 50;
        MaxValue = 100;

        InitializeComponent();
        Debug.WriteLine("Components done.");
    }

也许这很简单,或者我所说的方式是唯一的,但是如果图钉被编辑了,我不知道如何更新地图上的图钉,因为最终,它仍然是同一个对象,所以列表没有'不要改变......

感谢您的帮助!

编辑 1

好吧,我做了一些更改,但是仍然无法正常工作。我的意思是我的代码可以按我的意愿工作,但是调用 PropertyChanged 并没有改变任何内容...

我改变了一些东西,比如 List&lt;CustomPin&gt; 现在是 ObservableCollection&lt;CustomPin&gt;.. 我还把 xaml 部分改成了:

<control:CustomMap x:Name="MapTest" CustomPins="{Binding CustomPins}" CameraFocusParameter="OnPins"
                   PinSize="{Binding PinsSize, Converter={StaticResource Uint}}"
                   PinClickedCallback="{Binding PinActionClicked}"
                   VerticalOptions="Fill" HorizontalOptions="Fill"/>

而我的CustomPin 现在是这样的:

public class CustomPin : BindableObject, INotifyPropertyChanged
{
    /// <summary>
    /// Handler for event of updating or changing the 
    /// </summary>
    public event PropertyChangedEventHandler PropertyChanged;

    public static readonly BindableProperty AddressProperty =
        BindableProperty.Create(nameof(Address), typeof(string), typeof(CustomPin), "",
            propertyChanged: OnAddressPropertyChanged);
    public string Address
    {
        get { return (string)GetValue(AddressProperty); }
        set { SetValue(AddressProperty, value); }
    }
    private static void OnAddressPropertyChanged(BindableObject bindable, object oldValue, object newValue)
    {
        (bindable as CustomPin).SetAddress(newValue as string);
        Debug.WriteLine("Address property changed");
    }
    private async void SetAddress(string address)
    {
        if (setter == SetFrom.None)
        {
            setter = SetFrom.Address;
            SetLocation(await CustomMap.GetAddressPosition(address));
            setter = SetFrom.None;
            NotifyChanges();
        }
        else if (setter == SetFrom.Location)
        {
            setter = SetFrom.Done;
            SetValue(AddressProperty, address);
        }
    }

    private enum SetFrom
    {
        Address,
        Done,
        Location,
        None,
    }
    private SetFrom setter;

    private async void SetLocation(Position location)
    {
        if (setter == SetFrom.None)
        {
            setter = SetFrom.Location;
            SetAddress(await CustomMap.GetAddressName(location));
            setter = SetFrom.None;
            NotifyChanges();
        }
        else if (setter == SetFrom.Address)
        {
            setter = SetFrom.Done;
            SetValue(LocationProperty, location);
        }
    }

    public static readonly BindableProperty LocationProperty =
      BindableProperty.Create(nameof(Location), typeof(Position), typeof(CustomPin), new Position(),
          propertyChanged: OnLocationPropertyChanged);
    public Position Location
    {
        get { return (Position)GetValue(LocationProperty); }
        set { SetValue(LocationProperty, value); }
    }
    private static async void OnLocationPropertyChanged(BindableObject bindable, object oldValue, object newValue)
    {
        (bindable as CustomPin).SetLocation((Position)newValue);
        Debug.WriteLine("Location property changed");
    }

    private void NotifyChanges()
    {
        this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Address)));
        this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Location)));
    }

    public string Name { get; set; }
    public string Details { get; set; }
    public string ImagePath { get; set; }
    public uint PinSize { get; set; }
    public uint PinZoomVisibilityMinimumLimit { get; set; }
    public uint PinZoomVisibilityMaximumLimit { get; set; }
    public Point AnchorPoint { get; set; }
    public Action<CustomPin> PinClickedCallback { get; set; }

    public CustomPin(Position location)
    {
        setter = SetFrom.None;
        Location = location;
        Name = "";
        Details = "";
        ImagePath = "";
        PinSize = 50;
        PinZoomVisibilityMinimumLimit = uint.MinValue;
        PinZoomVisibilityMaximumLimit = uint.MaxValue;
        AnchorPoint = new Point(0.5, 1);
        PinClickedCallback = null;
    }
    public CustomPin(string address)
    {
        setter = SetFrom.None;
        Address = address;
        Name = "";
        Details = "";
        ImagePath = "";
        PinSize = 50;
        PinZoomVisibilityMinimumLimit = uint.MinValue;
        PinZoomVisibilityMaximumLimit = uint.MaxValue;
        AnchorPoint = new Point(0.5, 1);
        PinClickedCallback = null;
    }
    public CustomPin()
    {
        setter = SetFrom.None;
        Address = "";
        Location = new Position();
        Name = "";
        Details = "";
        ImagePath = "";
        PinSize = 50;
        PinZoomVisibilityMinimumLimit = uint.MinValue;
        PinZoomVisibilityMaximumLimit = uint.MaxValue;
        AnchorPoint = new Point(0.5, 1);
        PinClickedCallback = null;
    }
}

最后,PropertyChanged 的调用没有任何作用.. 有什么想法吗?

谢谢!

PS:不要忘记我的 github 存储库中提供了该解决方案

【问题讨论】:

  • 您的 Pin 需要实现 INotifyPropertyChanged
  • 好的,但是属性改变的参数是什么?
  • 被更改的属性的名称
  • 您好,我编辑了问题,您能再看一下吗?谢谢

标签: c# list xamarin.forms


【解决方案1】:

您应该在 Pin 实现中使用 INotifyPropertyChanged。这样,当您更新某些参数时,您会通知更改并可以更新地图。

【讨论】:

  • 您好,我编辑了问题,您能再看一下吗?谢谢
【解决方案2】:

不久前遇到了类似的问题,为我解决的问题是从以下位置更改 xaml 中的绑定:

CustomPins="{Binding CustomPins}"

到这里:

CustomPins="{Binding CustomPins, Mode=TwoWay}"

【讨论】:

    【解决方案3】:

    我终于有了主意!在 Xamarin 表单中,App 可以从任何地方访问,所以我所做的是:

    • 在您的MainPage.xaml.cs 中创建一个调用PropertyChanged 事件的方法。你可以这样做:

      public void PinsCollectionChanged()
      {
          this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CustomPins)));
          Debug.WriteLine("Updated !!!");
      }
      
    • 然后,从列表中的项目(对我来说是CustomPin 对象)中,通过获取应用程序的当前实例来调用此方法。看看代码就明白了:

      private void NotifyChanges()
      {
          (App.Current.MainPage as MainPage).PinsCollectionChanged();
      }
      

    PS:不要忘记在你的对象中添加using MapPinsProject.Page;

    希望对你有帮助!

    【讨论】:

      猜你喜欢
      • 2012-09-25
      • 1970-01-01
      • 2023-01-16
      • 2011-11-03
      • 2011-06-15
      • 1970-01-01
      • 2011-02-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多