首页 > 解决方案 > 后台任务正在阻塞 wpf .net 核心应用程序中的主线程

问题描述

我的软件中有一个后台任务,应该无限期运行。

重复该任务(以及将来可能还有其他任务)的代码如下所示:

public class RunTicketTasks
{
    public async Task RunBackgroundTasks()
    {
        AssignTickets assignTickets = new AssignTickets();
        while (true)
        {
            await assignTickets.AssignTicketCreator();
            await Task.Delay(5 * 60 * 1000);
        }
    }
}

同时MainWindow.xaml,据我所知,我有 WPF UI,它是应用程序的入口点。

public MainWindow我开始任务的方式如下:

public MainWindow()
{ 
    InitializeComponent();
    JiraBackgroundTasks.RunTicketTasks ticketTasks = new JiraBackgroundTasks.RunTicketTasks();
    ticketTasks.RunBackgroundTasks();
}

显然,这会在同一个线程上启动任务(我相信)。任务已启动并成功运行,但由于长时间运行操作,UI 被阻塞。同时,当我取消注释最后一行时ticketTasks.RunBackgroundTasks();,UI 运行良好。

如何在后台启动任务以使我的用户界面仍然响应?

编辑:
我以这种方式开始任务的原因是异常处理。我可以按照建议在不同的线程上成功启动任务Task.Run(async () => await ticketTasks.RunBackgroundTasks());但是如果出现问题,我将不会收到任何异常。

如果抛出异常,如何启动不阻塞 UI 的任务并仍接收异常详细信息?

网上说的方法如下:

await Task.Run(() => ticketTasks.RunBackgroundTasks());

但这行不通,因为The await operator can only be used within an async method.

标签: c#user-interfaceasynchronoustask

解决方案


一种方法是将任务包装在异步事件回调中:


public partial class MainWindow : Window
{
    // I mocked your missing types, replace with your own 
    class AssignTickets
    {
        public Task AssignTicketCreator() => Task.CompletedTask;
    }

    public class RunTicketTasks
    {
        public async Task RunBackgroundTasks()
        {
            AssignTickets assignTickets = new AssignTickets();
            int x = 0;
            while (true)
            {
                await assignTickets.AssignTicketCreator();
                await Task.Delay(1000);

                var isRunningOnDispatcher = Application.Current.Dispatcher ==
                    System.Windows.Threading.Dispatcher.FromThread(Thread.CurrentThread);
                Trace.WriteLine($"One second passed, running on dispatcher: {isRunningOnDispatcher}");

                // exception will also get thrown on the main thread
                if (x++ > 3) throw new Exception("Hello!");
            }
        }
    }

    public MainWindow()
    {
        InitializeComponent();

        // event fires on UI thread!
        this.Loaded += async (sender, args) =>
        {
            try
            {
                await new RunTicketTasks().RunBackgroundTasks();
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);
            }
        };
    }
}


推荐阅读