I'm trying to implement async await into my application and I'm running into some difficulties
in what looks easy yet it's not working out as such. I have the code below which I would have through awaiting the LoadAsync would perform the WCF service call and return the data, then I could load the Tasks form. However with the await call I get a cross-ui thread exception on the instancing of the Tasks form. If I remove await then it works. What am I doing wrong?
if (!Core.Tasks.IsLoaded)
{
await Core.Tasks.LoadAsync();
}
Core.ShowWait("Opening Tasks");
TasksForm frm = new TasksForm() { MdiParent = Core.MainMDIWindow, CurrentViewName = Core.CurrentUser.UserProfile.TasksLastViewName }; // <-- error on this line
The LoadAsync method is:
public override Task LoadAsync(bool includeDeleted = false)
{
return Task.Run(async () =>
{
Core.Logger.EnterMethod("_TasksData.Load");
try
{
DataSet = Core.LogbookProData.Tasks.GetTasks(DataUserID, includeDeleted);
LoadCompleted();
dsTasks cacheData = await Cache.LoadAsync(ConvertTimeZone);
if (cacheData != null)
MergeDataSets(DataSet, cacheData);
InitializeLayouts();
}
catch (Exception ex)
{
Core.Logger.LogException("_TasksData.Load", ex);
}
finally
{
Core.Logger.LeaveMethod("_TasksData.Load");
}
});
}
You cannot access any UI objects from a background thread. Task.Run
executes its delegate on a background thread, so if there's anything in the Task.Run
delegate that accesses the UI (e.g., InitializeLayouts
sounds suspect), then you'll get an exception like this.
Task.Run
should really only be used if you have a CPU-bound operation, or if you only have a blocking API for what shoud be an asynchronous call. It's not normally used to implement async
methods. You may find my async
/await
intro post helpful.
For example, if GetTasks
and MergeDataSets
do not block too long, you could implement LoadAsync
like this:
public override async Task LoadAsync(bool includeDeleted = false)
{
Core.Logger.EnterMethod("_TasksData.Load");
try
{
DataSet = Core.LogbookProData.Tasks.GetTasks(DataUserID, includeDeleted);
LoadCompleted();
dsTasks cacheData = await Cache.LoadAsync(ConvertTimeZone);
if (cacheData != null)
MergeDataSets(DataSet, cacheData);
InitializeLayouts();
}
catch (Exception ex)
{
Core.Logger.LogException("_TasksData.Load", ex);
}
finally
{
Core.Logger.LeaveMethod("_TasksData.Load");
}
}