Forum Visual Studio

Xamarin Forms Map not adding pins on new pin created

I have a Xamarin Forms map that shows a collection of Pins. When I add a new location it doesn't show the newly created pin until I click 'Refresh'.

I originally had the AddLocation subscribe in the constructor of the ViewModel and it worked, but added the pin 3 times to the database and map. Its since moving the AddLocation subscribe and unsubscribe to their own methods in the ViewModel and calling then OnAppearing() and OnDisappearing() that the new pin doesnt show.

The map is on a page called ItemPage.xaml

<ContentPage.ToolbarItems>


</ContentPage.ToolbarItems>

<ContentPage.Content>


</ContentPage.Content>

and the Code Behind -

[DesignTimeVisible(false)]
public partial class ItemPage : ContentPage
{
ItemViewModel viewModel;

public ItemPage()
{
    InitializeComponent();

    BindingContext = viewModel = new ItemViewModel();
}

private void Button_Clicked(object sender, EventArgs e)
{

}

protected override void OnAppearing()
{
    base.OnAppearing();
}

async void ToolbarItem_Clicked(object sender, EventArgs e)
{
    await Navigation.PushModalAsync(new NavigationPage(new NewLocationPage()));
}

private void ToolbarItem_Clicked_1(object sender, EventArgs e)
{
    viewModel.LoadLocationsCommand.Execute(null);
}

}

The View Model -

public class ItemViewModel : BaseViewModel
{

public ObservableCollection<MapPinModel> Locations { get; set; }

public ObservableCollection<ItemModel> Items { get; set; }

public Command LoadLocationsCommand { get; set; }

public Command LoadItemsCommand { get; set; }

public Map Map { get; private set; }

public ItemViewModel()
{
    Title = "Items";
    Locations = new ObservableCollection<MapPinModel>();
    Items = new ObservableCollection<ItemModel>();

    LoadLocationsCommand = new Command(async () => await ExecuteLoadLocationsCommand());

    LoadItemsCommand = new Command(async () => await ExecuteLoadItemsCommand());



    Map = new Map(MapSpan.FromCenterAndRadius(
        new Xamarin.Forms.Maps.Position(53.70251232638285, -1.8018436431884768),
        Distance.FromMiles(0.5)))
    {
        IsShowingUser = true,
        VerticalOptions = LayoutOptions.FillAndExpand
    };

    this.LoadLocationsCommand.Execute(null);
}

public void UnsubscribeMessages()
{
    MessagingCenter.Unsubscribe<NewLocationPage, ItemLocationModel>(this, "AddLocation");
}

public void SubscribeMessages()
{
    MessagingCenter.Subscribe<NewLocationPage, ItemLocationModel>(this, "AddLocation", async (obj, item) =>
    {
        await ItemDataStore.AddItemLocationAsync(item);
    });
}

async Task ExecuteLoadItemsCommand()
{
    if (IsBusy)
        return;

    try
    {
        Items.Clear();
        var items = await ItemDataStore.GetItemsAsync(true);

        foreach (var item in items)
        {
            Items.Add(item);
        }
    }
    catch (Exception ex)
    {
        Debug.WriteLine(ex);
    }
    finally
    {
        IsBusy = false;
    }
}

async Task ExecuteLoadLocationsCommand()
{
    Map.Pins.Clear();

    var locations = await ItemDataStore.GetLocationsAsync(true);

    foreach (Feature feature in locations.Features)
    {
        if (!feature.Geometry.Type.Equals(GeoJSONObjectType.Point))
            continue;

        Point point = feature.Geometry as Point;

        GeoJSON.Net.Geometry.Position s = point.Coordinates as GeoJSON.Net.Geometry.Position;

        MapPinModel pin = new MapPinModel
        {
            PopupContent = feature.Properties["popupContent"].ToString(),
            ScientificName = feature.Properties["scientificname"].ToString(),
            ItemDescription = feature.Properties["description"].ToString(),
            AddedBy = feature.Properties["username"].ToString(),
            Latitude = s.Latitude.ToString(),
            Longitude = s.Longitude.ToString()
        };

        Xamarin.Forms.Maps.Position position = new Xamarin.Forms.Maps.Position(Convert.ToDouble(pin.Latitude), Convert.ToDouble(pin.Longitude));

        Pin newPin = new Pin
        {
            Label = pin.PopupContent,
            Type = PinType.Place,
            Position = position
        };

        Map.Pins.Add(newPin);
    }
}

}

Finally the New Location page -

[DesignTimeVisible(false)]
public partial class NewLocationPage : ContentPage
{
ItemViewModel viewModel;

public ItemLocationModel Location { get; set; }

public NewLocationPage()
{
    InitializeComponent();

    Location = new ItemLocationModel();

    BindingContext = viewModel = new ItemViewModel();

    BindingContext = this;

    viewModel.SubscribeMessages();
}

async void Save_Clicked(object sender, EventArgs e)
{
    var location = await Geolocation.GetLastKnownLocationAsync();

    Location.Latitude = location.Latitude.ToString();
    Location.Longitude = location.Longitude.ToString();

    Location.DatePosted = DateTime.Now;

    Location.ItemId = ((ItemModel)itemsPicker.SelectedItem).Id;

    Location.SecretLocation = secretLocation.IsToggled;

    MessagingCenter.Send(this, "AddLocation", Location);

    await Navigation.PopModalAsync();

    Location = null;

}

async void Cancel_Clicked(object sender, EventArgs e)
{
    await Navigation.PopModalAsync();
}

protected override void OnAppearing()
{
    viewModel.SubscribeMessages();

    base.OnAppearing();

    if (viewModel.Items.Count == 0)
        viewModel.LoadItemsCommand.Execute(null);

    itemsPicker.ItemsSource = viewModel.Items;
}

protected override void OnDisappearing()
{
    viewModel.LoadLocationsCommand.Execute(null);

    viewModel.UnsubscribeMessages();

    base.OnDisappearing();
}

}

Sign In or Register to comment.