简体   繁体   中英

Cross UI thread invalid operation with async await

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM