【问题标题】:Task in child window suspend UI子窗口中的任务暂停 UI
【发布时间】:2014-09-09 12:18:56
【问题描述】:

我有AuthenticateWindowMainWindow,标记和代码在下面公开。它非常简化。当在MainWindow 构造函数中我使用Thread 类时,它工作正常,但如果我使用Task 类,UI 将被挂起,即在Thread.Sleep(5000); 过去时不显示'MainWindow'。是否可以在不暂停任何 UI 的情况下使用 Task 类(因为我需要它的取消机制和 Status 属性)?

重要条件:我无法修复AuthWindow 中的代码。

验证窗口:

xaml

<Grid>
    <Button Content="OpenMainWindow"
            Click="ButtonBase_OnClick"></Button>
</Grid>

c#

public partial class AuthWindow : Window
{
    public AuthWindow()
    {
        InitializeComponent();
    }

    private void DoAbsolutelyNothing()
    {

    }

    private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
    {
        Task.Factory.StartNew(DoAbsolutelyNothing).ContinueWith(t =>
        {
            var window = new MainWindow();
            if (window.IsInitialized)
                window.Show();

            Close();
        }, TaskScheduler.FromCurrentSynchronizationContext());
    }
}

主窗口:

xaml

<Grid>
    <TextBlock Text="MainWindow"></TextBlock>
</Grid>

c#

public partial class MainWindow : Window
{
    private Task _task;

    private void TestMethod()
    {
        Thread.Sleep(5000);
        Debug.WriteLine("TestMethod comleted");
    }

    public MainWindow()
    {
        InitializeComponent();

        // it works badly  
        //_task = Task.Factory.StartNew(TestMethod);

        // it works fine
        new Thread(TestMethod).Start();
    }

    private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
    {

    }
}

Windows 7、.Net 4.0

重要提示:暴露的代码会重现问题,只需复制粘贴即可!

【问题讨论】:

  • 请详细定义“效果不佳”。这个电话的具体症状是什么?
  • 你调用_task.Wait();什么地方?
  • @Gusdor,正如我上面写的:UI 已暂停,即 Thread.Sleep(5000); 时未显示“MainWindow”;已过。
  • @George Vovos,上面的代码没有任何 _task.Wait(); 并且 UI 被暂停:(
  • 你为什么需要 _Task 变量?你的代码看起来没问题。我认为问题出在其他地方。当你简化代码时,你错过了一些东西

标签: c# wpf multithreading xaml task


【解决方案1】:

你必须强制任务在另一个线程上运行

Task.Factory.StartNew(TestMethod, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default);

更多:
Why Starting A New Task In The Task Parallel Library (TPL) Doesn’t Always Start A New Thread

【讨论】:

  • 它可以工作,但我认为Task 实例默认总是在另一个线程中运行,不是吗?
  • 我的印象是,使用默认调度程序启动的任务总是会租用一个 ThreadPoor 线程。这确实很奇怪。
  • 没错。但是这个任务没有使用默认调度器启动。检查这个stackoverflow.com/questions/6800705/…
  • Task 默认在另一个线程中运行,在您的情况下,您使用 TaskScheduler.FromCurrentSynchronizationContext() 强制它仍然在 UI 线程上工作。如果它不在后台运行,同步方法和任务之间会有什么区别?通常你使用 Task.Factory.StartNew(MyMethod),不需要像接受的答案那样使用所有这些选项。
  • @Maximus 你不能保证任务会在另一个线程上运行。(如果你使用 Task.Run 可以保证)stackoverflow.com/questions/12245935/…
【解决方案2】:

TaskScheduler.FromCurrentSynchronizationContext() 不是在 ThreadPool 同步上下文中创建任务,而是在调用它的上下文上创建任务,在这种情况下是从 UI 这就是它被冻结的原因。

【讨论】:

  • 我该怎么办?我不能拒绝 TaskScheduler.FromCurrentSynchronizationContext()
  • 一旦你摆脱它,它就会正常工作。即使您创建了 Task,它仍然会在 UI 线程上同步运行。
  • 但是创建新的MainWindow 实例的代码不会抛出异常,因为它不会在 UI 线程上运行吗?
  • @DanielKelley 可以使用Dispatcher Object来更新UI线程stackoverflow.com/questions/9602567/…
  • 如果您创建新窗口,则无需处理任务,因为您必须在 UI 线程上执行此操作。
猜你喜欢
  • 2014-11-04
  • 1970-01-01
  • 2015-03-26
  • 2012-07-20
  • 2017-10-10
  • 1970-01-01
  • 2018-07-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多