I am loading some data via WCF on the loading of a given page. I then want to populate a Picker with the values once the data has loaded. However, I'm getting a cross threading problem. Here is the code:
protected async override void OnAppearing()
{
base.OnAppearing();
await Task.Factory.StartNew(async () => { await Initialise(); });
}
private async Task Initialise()
{
var activities = await App.XivicServicesClient.DataAccessCalls.GetRecordsAsync<ActivityDef>(null, new ConnectionInfo(null, App.XivicServicesClient.AuthToken));
var activityCodes = activities.Select(a => a.Code);
foreach (var activityCode in activityCodes)
{
ActivityPicker.Items.Add(activityCode);
}
}
In Windows UWP, the error I get is
Additional information: The application called an interface that was marshalled for a different thread. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))
I guess that I am using the OnAppearing call in an unintended way, so how should I get around this? I need to make a Task Based Async WCF call when the page starts loading.
On iOS, I don't get the error.
Your problem comes from
ActivityPicker.Item.Add(activityCode);
That line may ONLY be run on the UI thread.
You can easily fix this code with the following
protected async override void OnAppearing()
{
base.OnAppearing();
var activityCodes = await Task.Factory.StartNew(async () => { await Initialise(); });
foreach (var activityCode in activityCodes)
{
ActivityPicker.Items.Add(activityCode);
}
}
private async Task<List<string>> Initialise()
{
var activities = await App.XivicServicesClient
.DataAccessCalls
.GetRecordsAsync<ActivityDef>(null, new ConnectionInfo(null, App.XivicServicesClient.AuthToken));
return activities.Select(a => a.Code).ToList();
}
However, I really doubt that you "need" to use Task.Factory.StartNew
. GetRecordsAsync
already is an async method. Chances are, most of the delay in Initialise
(sic) comes from the I/O latency.
Running Initialise
from another thread will only INCREASE the run time, as the data needs to be marshaled across threads, along with synchronization.
Rather, try.
protected async override void OnAppearing()
{
base.OnAppearing();
var activities = await App.XivicServicesClient
.DataAccessCalls
.GetRecordsAsync<ActivityDef>(null, new ConnectionInfo(null, App.XivicServicesClient.AuthToken));
foreach (var activityCode in activities.Select(a => a.Code))
{
ActivityPicker.Items.Add(activityCode);
}
}
The problem was simple. I'd added code that wasn't necessary, and that code was causing the bug. Here is the fixed method:
protected async override void OnAppearing()
{
base.OnAppearing();
await Initialise();
}
User contributions licensed under CC BY-SA 3.0