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