【问题标题】:WPF Async Task locking UIWPF 异步任务锁定 UI
【发布时间】:2014-11-04 07:38:26
【问题描述】:

我知道我错过了一些愚蠢的东西,“StartProcess”方法使 UI 没有响应,并且没有多少谷歌搜索和教程让我得到答案。

这是我的代码:

    public MainWindow()
    {
        InitializeComponent();
        txtBlock.Text = "Testing";
        Initialize();
    }

    public void Initialize()
    {
        uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();

        StartProcess();
    }

    async void StartProcess()
    {
         Task<int> result = Task.Factory.StartNew(() =>
        {
            txtBlock.Text += ("\n starting updater");
            while (true)
            {
                Thread.Sleep(3000);
            }
            return 0;
        }, CancellationToken.None, TaskCreationOptions.LongRunning, uiScheduler);
    }

一些背景知识:我正在构建一个应用程序,该应用程序必须每 5 分钟轮询一次数据库,并使用用户的待办事项列表更新 UI,因此是 while(true) 循环。该应用程序必须在其整个生命周期内不断地轮询数据库。

【问题讨论】:

  • 您可以尝试使用Task.Delay 而不是Thread.Sleep。目前,您似乎在 UI 线程上调用 Thread.Sleep,这将使您的 UI 无响应。此外,简单地使您的方法 async 不会发挥作用。
  • 你应该看看Rx
  • 这个答案可能有用stackoverflow.com/questions/4253088/…

标签: wpf async-await


【解决方案1】:

嗯,你要求 TPL 在 UI 线程中调用 Func,它听从你的话。

在 StartNew 中,您将 uiScheduler 传递为 TaskScheduler,因此任务将排队到 Dispatcher,这将由 UI 线程调用。

如果您不想在 UI 线程中执行,请使用TaskScheduler.Default,这样做您无法在Func 中更新txtBlock.Text。您需要编组对 UI 线程的调用,或者只需将 txtBlock.Text 设置在 Func 之外 StartNew 之前。

如果您在 .Net 4.5 中,请始终首选 Task.Run,请注意 StartNew is dangerous

需要注意的几点:

  • 请注意,您根本没有使用async 功能。没有 await 关键字方法根本不是异步的。你不需要 async 关键字(事实上你会得到一个编译器警告,请付费 注意编译器所说的)。
  • 避免异步 void 方法(事件处理程序中除外),如果您不需要任何返回值,请始终使用 async Task,以便您可以在调用者中等待它或附加继续等等。

更新添加一些代码:

async Task StartProcess()
{
    while (true)
    {
        var result = await Task.Run(()=> MethodWhichCallsDBAndReturnsSomething());
        txtBlock.Text = result.ToString();//Use result and update UI
        await Task.Delay(5 * 60 * 1000);//await 5 mins
    }
}

【讨论】:

  • 关于您的最后一行 - 然后他们需要编组任何调用以将 UI 更新回 UI 线程(您无疑知道,但可能 OP 不知道)。
  • @DanielKelley 我正在更新我的答案。你太快了:)
  • 感谢 sriram,内容丰富。我将如何将 await 关键字合并到假设永久运行的任务中?我的目标是启动一个工作线程,每 5 分钟轮询一次数据库,并在返回相关数据时更新用户界面。
  • @Swifty 更新了我的答案,看看是否有帮助。如果您需要更多帮助,请发表评论。
  • @Swifty 这将是更高效的 IMO。 await Task.Delay 没有创建任何线程。它只是在内部设置了一个计时器。所以从技术上讲,我们不会浪费任何线程。同样在await Task.Run 中,我们不一定要创建一个新线程(我们使用的是线程池中已经存在的线程)。如果您想完全创建一个新线程并将 UI 工作传递给调度员,请查看我最近的回答和斯科特的回答 hereIProgress&lt;T&gt; 是您将要使用的东西。
猜你喜欢
  • 1970-01-01
  • 2016-04-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-13
  • 1970-01-01
  • 2020-08-25
  • 1970-01-01
相关资源
最近更新 更多