After making the project simpler, I believe I identified the problem is actually a result the async marshalling.
UPDATE: I made the code simpler to try to figure out what was going on. So here is an update... The Observable collection is being populated on a new thread (async method). I tried moving the assigning of the ItemsSource to after the ObservableCollection is loaded as seen below
   async void LoadAllData(object sender, EventArgs e)
    {
        if (sender != null)
        {
            App.GeoLocationComplete -= LoadAllData;
        }
await ViewModelObjects.NearbyLocations.LoadLocationData();
lvPlaces.ItemsSource = ViewModelObjects.NearbyLocations.GBSLocationDetails;
}
The definition for the data load method is a follows:
public async Task LoadLocationData()
    {....}
When I run this code I get the following error:
The application called an interface that was marshalled for a different thread. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))
I know what is causing the error (the data was loaded on a thread other than the UI thread) but I don't know how to fix it. Suggestions?
UPDATE UPDATE: So I believe I have identified the root cause of the problem but have not figured out how to fix it. I started by simplifying my code as follows and it worked.
    public nearbyplaces()
    {
        InitializeComponent();
        NavigationPage.SetHasNavigationBar(this, false);
        LoadAllData(null, null);
    }
    void LoadAllData(object sender, EventArgs e)
    {
        lobj_Places = new ObservableCollection<GBSLocationDetail>()
        {
            new GBSLocationDetail()
            {
                Title = "Location 1",
                Distance = "20 Miles",
                AddInfo = "Something Else",
                AttributesTexts="Gay, Bar, Dance"
            }
        };
        lvPlaces.ItemsSource = lobj_Places;
    }
HOWEVER, what I need is for the LoadAllData method to be called once I have the GPS location from the device. So in my App.XAML.cs I have the following delegate event declared:
    public static Plugin.Geolocator.Abstractions.IGeolocator gobj_RealGeoCoordinator;
    public static event GeoLocationCompleteEventHandler GeoLocationComplete;
    public static bool gb_WaitingForLocation = true;
Then I have the following code call the event once I get the location back from the device:
   private async void ProcessStartupandResume()
    {
        if (gobj_RealGeoCoordinator == null)
        {
            gobj_RealGeoCoordinator = CrossGeolocator.Current;
            ViewModelObjects.AppSettings.CanAccessLocation = App.gobj_RealGeoCoordinator.IsGeolocationEnabled;
            if (!ViewModelObjects.AppSettings.CanAccessLocation)
            {
                await MainPage.DisplayAlert(ResourceStrings.GetValue("NoLocationServicesTitle"), ResourceStrings.GetValue("NoLocationServicesMessage"), ResourceStrings.GetValue("OKButtonText"));
            }
            //Only add the events if the object has to be created. 
            gobj_RealGeoCoordinator.PositionChanged += gobj_RealGeoCoordinator_PositionChanged;
            gobj_RealGeoCoordinator.PositionError += (sender, e) =>
            {
                ProcessException(new Exception(e.Error.ToString()));
            };
        }
        //Set this to null to trigger the first check
        ib_GPSReenabled = null;
        if (gobj_RealGeoCoordinator.IsListening)
            await gobj_RealGeoCoordinator.StopListeningAsync();
        gobj_RealGeoCoordinator.DesiredAccuracy = 50;
        await gobj_RealGeoCoordinator.StartListeningAsync(10000, 20);
    }
    private static void gobj_RealGeoCoordinator_PositionChanged(object sender, PositionEventArgs e)
    {
        var pos = e.Position;
        ViewModelObjects.AppSettings.Latitude = pos.Latitude;
        ViewModelObjects.AppSettings.Longitude = pos.Longitude;
        if (gb_WaitingForLocation)
        {
            gb_WaitingForLocation = false;
            GeoLocationComplete?.Invoke(new object() , null);
        }
    }
Then in my page I subscribe to the GeoLocationComplete event using the LoadAllData method as seen below. Even when I use a local object and try to set the ItemsSource for the ListView in the code when executed as a result of the event being raised, I receive the error. See code below which subscribed to the event:
    public nearbyplaces()
    {
        InitializeComponent();
        NavigationPage.SetHasNavigationBar(this, false);
        if (App.gb_WaitingForLocation)
            App.GeoLocationComplete += LoadAllData;
        else
            LoadAllData(null, null);
    }
Any suggestions on how to fix this?
OK so I figured it out. I needed to invoke the event on the main thread and I did that with the following code:
      Device.BeginInvokeOnMainThread(() =>
            {
                GeoLocationComplete?.Invoke(new object(), null);
            });
After inserting this code, the error was gone. Changing the code back to simply
GeoLocationComplete?.Invoke(new object(), null);
cause the error to occur again. Thus I believe this resolved my problem. Hope this helps someone else. :)
User contributions licensed under CC BY-SA 3.0