How to bind map/pin in view model properly in Xamarin.Forms?

973 Views Asked by At

I followed the doc, trying to bind the pin, but failed. The map is always showing the default position Rome. Here is the source code:

In DetailPage.xmal:

               <Frame Margin="10,5"
                       CornerRadius="10"
                       Padding="0">
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="300" />
                        </Grid.RowDefinitions>
                        <maps:Map MapType="Street" Grid.Row="0" ItemsSource="{Binding WorkPlace}">
                            <maps:Map.ItemTemplate>
                                <DataTemplate>
                                    <maps:Pin Position="{Binding Position}"
                                              Address="{Binding Address}"
                                              Label="{Binding Description}" />
                                </DataTemplate>
                            </maps:Map.ItemTemplate>
                        </maps:Map>
                    </Grid>
                </Frame>

In DetailPageModel.cs:

public class DetailPageModel : PageModelBase
    {
        private Timesheet _detailedTimesheet;
        
        private ObservableCollection<Location> _workPlace;
        public ObservableCollection<Location> WorkPlace
        {
            get => _workPlace;
            set => SetProperty(ref _workPlace, value);
        }
        
        
        public ReportDetailPageModel()
        {
            
        }
   
        public override async Task InitializeAsync(object navigationData)
        {
            if (navigationData is Timesheet selectedTimesheet)
            {
                _detailedTimesheet = selectedTimesheet;
              
                WorkPlace = new ObservableCollection<Location>()
                {
                    new Location(
                        _detailedTimesheet.ProjectAddress, 
                        "Test Location", 
                        new Position(_detailedTimesheet.ProjectLatitude, _detailedTimesheet.ProjectLongitude))                   
                };
                
            }
            
            await base.InitializeAsync(navigationData);
        }
    }

In Location.cs:

public class Location : ExtendedBindableObject
    {
        Position _position;

        public string Address { get; }
        public string Description { get; }

        public Position Position
        {
            get => _position;
            set => SetProperty(ref _position, value);
        }

        public Location(string address, string description, Position position)
        {
            Address = address;
            Description = description;
            Position = position;
        }
    }

In ExtendedBindableObject.cs:

protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
        {
            if (EqualityComparer<T>.Default.Equals(storage, value))
            {
                return false;
            }

            storage = value;
            OnPropertyChanged(propertyName);

            return true;
        }

Since the navigationData is correctly received in view model and the page's binding context is also working, I just don't know what could be missing. Any hint would be appreciated!

And actually I have one more confusion, why does the official doc use a custom Location class instead of the Pin class, as Pin inherits from Element/BindableObject/Object?

0

There are 0 best solutions below