使用异步等待交叉UI线程无效操作

时间:2013-06-02 00:34:32

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

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

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

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

1 个答案:

答案 0 :(得分:2)

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

实际上只有在你有CPU绑定操作的情况下才会使用

Task.Run,或者只有 shoud 是异步调用的阻塞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");
    }
}