I'm creating a small universal windows application. I'd like to use MapControl to present some data downloaded from the Internet. This data refreshes every minute and I want to update MapIcons positions everytime that it happens. So... After loading a map, I create a Timer that runs every 60 seconds and downloads the data using HttpWebRequest, then parses received JSON and then updates the positions of MapIcons displayed in MapControl.
Everything should work fine, however when I call new MapIcon() in Timer callback I have an exception:
An exception of type 'System.Exception' occurred in newproject.exe but was not handled in user code
Additional information: The application called an interface that was marshalled for a different thread. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))
My Timer callback code is:
private async void OnTimerTick(Object stateInfo)
{
var TramDataList = await Loader.LoadData();
updateMarkers(TramDataList);
}
private void updateMarkers(List<TramData> tramList)
{
lock (TramMarkerDict)
{
foreach (var tramData in tramList)
{
if (!TramDataDict.ContainsKey(tramData.Id))
{
TramDataDict.Remove(tramData.Id);
TramMarkerDict.Remove(tramData.Id);
}
}
foreach (var tramData in tramList)
{
TramData tmp = null;
var exists = TramDataDict.TryGetValue(tramData.Id, out tmp);
if (exists)
tmp.update(tramData);
else
TramDataDict.Add(tramData.Id, tramData);
}
foreach (var tramData in TramDataDict.Values)
{
MapIcon mapIcon = null;
var geopoint = new Windows.Devices.Geolocation.Geopoint(
new Windows.Devices.Geolocation.BasicGeoposition { Latitude = tramData.Lat, Longitude = tramData.Lng });
var exists = TramMarkerDict.TryGetValue(tramData.Id, out mapIcon);
if (exists)
mapIcon.Location = geopoint;
else
{
mapIcon = new MapIcon { Location = geopoint, Title = tramData.FirstLine, NormalizedAnchorPoint = new Point(0.5, 1) };
TramMarkerDict.Add(tramData.Id, mapIcon);
}
}
}
}
Please try using a Dispatcher. You need to add MapIcon objects on the UI Thread.
private async void MainPage_Loaded(object sender, RoutedEventArgs e)
{
await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
// Your Code
});
}
Although Jean-Sébastien Dupuy's answer is technically correct, another option is to use HttpClient
instead of HttpWebRequest
and use the await
keyword to ensure everything automatically runs on the correct thread. (Also make sure you're using a DispatcherTimer
and not some other kind of timer).
User contributions licensed under CC BY-SA 3.0