执行按钮单击时使 wpf UI 响应

问题描述 投票:0回答:7

在我的wpf(c#)应用程序中,当用户按下按钮时会执行一个很长的过程。当按下按钮直到执行完整的代码时,窗口将冻结,用户无法在窗口中执行任何其他任务。如何使按钮单击代码作为后台进程,以便窗口响应用户。我尝试过以下方法,但没有成功。

private void btn_convert_Click(object sender, RoutedEventArgs e)
{
    Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, 
    new Action(() => { 

         WorkerMethod();
    }));
}

其中WorkerMethod是包含整个代码的函数。有什么建议吗

问候,
桑吉塔

c# wpf multithreading background-process
7个回答
13
投票

如果您的目标是 .NET 4.5,您可以使用

async/await
使您的 UI 响应式:

private async void btn_convert_Click(object sender, RoutedEventArgs e)
{
    await WorkerMethod();
}

修改您的

WorkerMethod

private Task WorkerMethod()
{
    return Task.Run(() =>
        {
           // your long running task here
        });
}

7
投票

您实际上在这里所做的是要求 UI 线程通过 Dispatcher 运行您的繁重任务。

您应该创建一个新线程/任务并让它运行您的后台方法:

Thread t = new Thread(() => WorkerMethod());
t.Start();

欲了解更多信息,请阅读:

WPF 后台工作人员与调度程序

了解 WPF 中的“调度程序”


7
投票

这里答案的替代方案是BackgroundWorker。 它还有一个额外的好处,就是在完成后返回到 GUI 线程。

private void btn_convert_Click(object sender, RoutedEventArgs e)
{
    BackgroundWorker worker = new BackgroundWorker();
    worker.DoWork += WorkerMethod;
    worker.RunWorkerCompleted += WorkerEnded;
    worker.RunWorkerAsync();
}

private void WorkerMethod()
{
    // New thread, cannot access GUI
}

private void WorkerEnded()
{
    // Back on the GUI Thread
    // Worker is finished
}

1
投票

您正在调用

UI-Dispatcher
上的方法,这将使 UI 冻结。使用

在您的点击事件中创建一个新线程
private void btn_convert_Click(object sender, RoutedEventArgs e)
    {
         Thread t = new Thread(new ThreadStart(WorkerMethod));
         //assign STA or MTA, etc....
         t.Start();
    }

查看此处,了解有关“System.Threading.Thread`的信息。


1
投票

我设想了另一种令我相当自豪的方式: 如果多线程的好处仅在于允许 IHM 为进度条设置动画,如果用户不应该在进程中与 ihm 交互,或者只是没有时间开发多线程并且您不能允许应用程序在没有反馈:

您可以开发一个加载程序,启动到另一个 STA 线程中,该线程创建另一个窗口并在冻结窗口的中间显示此加载程序。

这是我撰写的一篇文章以及此类解决方案的实现:

http://charly-studio.com/blog/a-loader-for-wpf-long-ui-process/

这是我使用组件的方式:

private void MainWindow_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    // Long UI process context
    using (new LongUIProcessContext("Wait while loading..."))
    {
        Thread.Sleep(2000);

        // Sub long ui process context
        using (new LongUIProcessContext("Wait while loading 2..."))
        {
            Thread.Sleep(2000);
        } 

        // Another sub long ui process context
        using (new LongUIProcessContext("Wait while loading 3..."))
        {
            Thread.Sleep(2000);
        }
    }
}

这是我建议的长凳的样子: long Ui process bench

这是我制作的工作台的直接链接,您可以在其中找到组件:

工作台解决方案直接下载


0
投票

尝试使用Backgroundworker类。您必须注册到 DoWork 事件并创建一个事件处理程序,将所有处理代码放入其中。您可以使用 RunWorkerAsync 方法启动工作线程。还有一种可以报告您的工人进度的方法“ReportProgress”。 RunWorkerCompleted 将在您的工作线程处理完您的代码时向您显示。尝试在网上搜索BackgroundWorker之后,你会发现很多如何使用它的示例


0
投票

这对我来说效果很好,并且保持 UI 响应:

Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Render, Sub() Return)
© www.soinside.com 2019 - 2024. All rights reserved.