【问题标题】:Application dispatcher invoke freezes the application应用程序调度程序调用冻结应用程序
【发布时间】:2015-06-24 11:47:09
【问题描述】:

我遇到了应用程序冻结的问题。让我解释一下我的场景,我有一个服务,它对数据库进行异步调用以获取项目列表,它由一个任务运行。在这个任务中我有一个 try catch 块,所以它看起来像这样

public Task<List<T>> ComboListAsync(int? id = null, EnumDTO dto = EnumDTO.Default)
    {
        return Task.Run(() =>
        {
            using (var context = new ContextService())
            {
                try
                {
                    return GetComboList(id, dto, context);
                }
                catch (Exception e)
                {
                    Handler.DatabaseConnectionException();
                    throw;
                }
            }
        });
    }

然后它抛出一个异常,因为 GetComboList 它只是这个(暂时)

    protected virtual List<T> GetComboList(int? id, EnumDTO dto, ContextService context)
    {
        throw new NotImplementedException();
    }

所以调用会捕获异常并进入这里

    public void Show(string message)
    {
        Message = message;
        Application.Current.Dispatcher.Invoke(() =>
        {
            dialogView = new DialogView() {DataContext = this, Owner = Application.Current.MainWindow};
            dialogView.ShowDialog();
        });
    }

现在调度程序冻结了应用程序,我尝试将其更改为使用开始调用,它也是如此。如果没有调度程序,我会收到一条错误消息,指出调用线程不是 STA。我只是想在对话框窗口中显示我的消息,即连接到数据库时出现问题。任何人都可以帮忙吗? 我在网上看了很多关于调度程序的线程,但没有一个真正显示可以解决我的问题的解决方案。

谢谢

编辑 调用 ComboListAsync 的代码

    protected override void RetrieveRelatedActiveLists()
    {
        MyCollection = service.ComboListAsync().Result;
    }

【问题讨论】:

  • 如果你在Show() 方法中放置一个断点,它会被命中吗? Invoke() 内部呢?另外,你能发布调用ComboListAsnyc()Show()的代码吗?
  • 必须是上面调用你的方法的一部分,它对我来说很好
  • @AndrewStephens 被选中并进入 Application.Current.Dispatcher 行,此时它返回 UI 并冻结

标签: wpf multithreading messagebox dispatcher


【解决方案1】:

由于调用代码使用.Result,因此出现死锁。

使用service.ComboListAsync().Result 使UI 线程等待此方法返回,当您在其中调用Application.Current.Dispatcher.Invoke 时,您正在向等待方法本身返回的UI 线程发送一条消息。

您必须像这样等待方法service.ComboListAsync()

  protected override async void RetrieveRelatedActiveLists()
  {
      MyCollection = await service.ComboListAsync();
  }

【讨论】:

  • 非常感谢,这样就解决了。我不明白为什么它实际上会发生,我认为Results实际上会调用await。
  • 好吧,它不会,Result 会阻塞线程,直到函数返回,将其视为同步等待。另一方面,await 关键字让线程运行并设置一个“书签”,当方法返回时,它会从书签点继续。这是异步等待。从技术上讲,它比这更复杂。喝杯咖啡,从这里开始:msdn.microsoft.com/en-us/library/hh191443.aspx
  • 非常感谢您的宝贵时间。我一定会读的。关于 await 我不喜欢的一件事,它继续运行代码并且它不会冻结,但是在此方法之后立即访问 MyCollection 并抛出空引用异常,而结果将返回UI 显示一些动画,并在其准备就绪时继续。所以我猜消耗 MyCollection 的代码也需要是异步的,但是消耗它的代码也是如此,所以最后一切都必须是异步的,因为一种方法依赖于另一种方法。
  • 是的,async/await 一直沿链下去。但如果你想一想,这是有道理的(你为什么要冻结 UI)。一种选择是使用任务延续,例如: service.ComboListAsync().ContinueWith( /* UpdateUI here */ ) 但我认为这里的更多细节非常丑陋 (msdn.microsoft.com/en-us/library/…)... 还有另一种方法,但是会完全改变你的代码,这是一个全新的世界。它被命名为 RxFramework (msdn.microsoft.com/en-us/data/gg577609.aspx)
  • 再次感谢您的回复,我想我只需要比我最初想象的更深入地调查它:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-04
  • 2015-01-25
相关资源
最近更新 更多