0

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");
        }
    });
}

1 답변


2

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");
    }
}


  • Thx - I tried removing the Task.Run but that made no difference. Very hard bug to track down sadly. - Neal
  • Take a look at the stack trace for the exception. That should give you a good starting point. - Stephen Cleary

Related

Latest