【问题标题】:Cross UI thread invalid operation with async await使用异步等待的跨 UI 线程无效操作
【发布时间】:2013-06-02 08:51:48
【问题描述】:

我正在尝试在我的应用程序中实现异步等待,但遇到了一些困难

看起来很简单,但实际上并不成功。我有下面的代码,通过等待 LoadAsync 将执行 WCF 服务调用并返回数据,然后我可以加载任务表单。但是,通过 await 调用,我在 Tasks 表单的实例化上得到了一个跨 ui 线程异常。如果我删除 await 那么它可以工作。我做错了什么?

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

LoadAsync 方法是:

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

【问题讨论】:

    标签: c# .net-4.5 async-await


    【解决方案1】:

    您不能从后台线程访问任何 UI 对象。 Task.Run 在后台线程上执行它的委托,所以如果 Task.Run 委托中有任何东西可以访问 UI(例如,InitializeLayouts 听起来很可疑),那么你会得到这样的异常。

    Task.Run 只有在你有一个 CPU 密集型操作时才应该使用,或者如果你只有一个阻塞 API,应该是一个异步调用。 通常不用于实现async 方法。你可以找到我的async/await intro post helpful

    例如,如果GetTasksMergeDataSets 不会阻塞太久,您可以像这样实现LoadAsync

    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 - 我尝试删除 Task.Run 但这没有任何区别。可悲的是很难追查到的错误。
    • 查看异常的堆栈跟踪。这应该会给你一个很好的起点。
    猜你喜欢
    • 1970-01-01
    • 2011-07-11
    • 1970-01-01
    • 2020-07-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多