6

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

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

         WorkerMethod();
    }));
}

其中 WorkerMethod 是包含整个代码的函数。任何建议。

问候,
桑吉萨

4

6 回答 6

12

如果你的目标是 .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
        });
}
于 2013-03-14T12:53:24.997 回答
7

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

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

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

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

WPF BackgroundWorker 与 Dispatcher

了解 WPF 中的“调度程序”

于 2013-03-14T12:40:46.173 回答
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
}
于 2013-03-14T12:43:04.817 回答
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”的信息。

于 2013-03-14T12:40:28.630 回答
1

我想象了另一种我非常自豪的方式:如果多线程仅允许 IHM 为进度条设置动画,如果用户不应该与确保进程的 ihm 交互,或者只是没有时间开发p多线程,你不能让你的应用程序在没有反馈的情况下冻结:

您可以开发一个加载器,该加载器启动到另一个 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);
        }
    }
}

这是我建议的替补席的样子: 长UI工艺台

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

bench 解决方案直接下载

于 2013-09-06T13:40:21.727 回答
0

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

于 2013-03-14T12:45:18.180 回答