后台工作者不工作 WPF

Background worker does not Work WPF

在我的 WPF 程序中,它花费了大量的处理时间并冻结了很长时间。

所以我决定使用后台工作者并在后台处理它。

但它不起作用。通过debug,程序停在Render3D()处。它不会抛出异常。就像你输入 return.

换句话说,它在达到 Render3D() 后什么都不做,只会 return.

(我没说会 return 因为我不确定,但行为与 return 相同)

    private readonly BackgroundWorker backgroundWorker = new BackgroundWorker();
    private AssetDeclaration _assetDeclaration = new AssetDeclaration();

    public MainWindow()
    {
        backgroundWorker.DoWork += backgroundWorker1_DoWork;
        backgroundWorker.ProgressChanged += backgroundWorker1_ProgressChanged;
        backgroundWorker.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
        InitializeComponent();
    }

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        for (int i = 1; i <= 1000; i++)
        {
            if (!((BackgroundWorker)sender).CancellationPending)
            {
                Render3D(); // will return at this point. (why?) or waiting for something to start?
                ((BackgroundWorker)sender).ReportProgress(i);
            }
            else
            {
                e.Cancel = true;
                break;
            }
        }
    }

    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        MessageBox.Show("Done!");//will show message box instant.
    }

    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        ProgressBar1.Value = e.ProgressPercentage;
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        //...Some work here before starting Hard job!
        //...From now i want to start heavy process in background.
        //...with report to progress bar at same time.
        backgroundWorker.RunWorkerAsync(100);
    }

Render3D() 在没有后台处理的情况下工作正常,但会冻结一段时间。

Render3D() 在 Partial class of MainWindow 中。因为有很多方法所以我决定把它们分开。

还有我如何在 backgroundWorker1_DoWork 之外使用 ReportProgress 。例如在 Render3D().

最后一件事:我想知道如何向用户显示完成了多少进程。

已解决!:

问题是因为我在 Render3D()

中设置了 Viewport3D

我将它从 Render3D 中分离出来,问题得到解决。感谢 Henk Holterman 的正确答案。

似乎有些任务无法在另一个线程中完成。通过错误报告,我发现无效任务正在设置 Viewport3D 属性。

此任务必须在主线程中完成。

下面是使后台工作程序停止运行的无效代码。

DefineCamera();
Viewport.Children.Add(model); // Must be run in Main thread.

还有这部分。

    private void DefineCamera()
    {
        PerspectiveCamera camera = new PerspectiveCamera
        {
            FieldOfView = 60
        };

        PositionCamera(camera);
        Viewport.Camera = camera; // Must be run in Main thread.
    }

在 WPF 的世界里,与您习惯的 Windows 表单不同,您应该考虑 Dispatcher。为此,您必须导入 System.Windows.Threading

    private void ThreadTask()
    {
        Thread.Sleep(TimeSpan.FromSeconds(5));

        this.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
                    (ThreadStart)delegate()
                    {
                        //Do some heavy task here...
                    });
    }

快速更新

为了 运行 来自按钮点击或其他任何功能的线程,添加这行代码:

    Thread thread = new Thread(new ThreadStart(ThreadTask));
    thread.Start();

这行代码相当于BackgroundWorker.RunWorkerAsync();

我强烈推荐使用 async/await。此功能是在 .NET 4.5 中引入的,用于将工作从主 WPF GUI 线程转移到使应用程序快速响应。

本质上,规则是使用 Task.Run[ 的组合将任何不与 GUI 交互的计算推送到后台线程上=24=]。再加上 Dispatcher.Invoke,你真的不需要其他任何东西。

例如,可能会从数据库中获取数据的慢速数据调用可能会被推送到后台线程,因此应用程序在等待 SQL 执行时会冻结。

我用它来使我编写的应用程序快速、响应迅速且活泼。

首先,您很难找到错误。

... the program stop at Render3D(). It does not throw exception. Its like when you put return.

实际发生的事情是你的方法抛出了一个异常,并被 Backgroundworker 捕获了。它被转移到 Completed 事件,但您必须在那里对其进行操作。

private void worker_Completed(object sender, RunWorkerCompletedEventArgs e) 
{
  // check error, check cancel, then use result
  if (e.Error != null)
  {
     // handle the error
  }
  else if (e.Cancelled)
  {
     // handle cancellation
  }
  else      
  {         
      // use the result(s) on the UI thread
  }    
  // general cleanup
}

看不到 e.Errore.Result 等同于在程序中有一个空的 catch{} 块。

有了错误处理,我们就有了

oh yes it shown Error. System.InvalidOperationException the calling thread cannot access this object because a different thread owns it

这表明您的 Render3D() 仍在某处与 GUI 交互。

基本建议是将所有计算(和 I/O、数据库)工作与 UI 工作分开。您可以在线程中 运行 CPU 绑定和 I/O 绑定 cod,但 GUI 是单线程的,您只能从主线程与其交互。