如何使我的代码适合后台工作者?

时间:2015-04-27 14:42:58

标签: c# multithreading backgroundworker

我已经建立了一个执行以下操作的表单:

  1. 抓取目录中的所有文件路径(文件采用指定的命名约定)
  2. 使用分隔符解析文件路径
  3. 输出具有指定格式的文本文件。
  4. 问题是,一些目录是数百个演出,它们会冻结表单UI,直到完成该过程。我已经完成了对背景工作者的一些阅读,据我了解,代码的数据密集部分属于DoWork方法。但是,当我尝试将我的代码实现到DoWork方法时,我遇到了#34;跨线程操作无效:"错误。我查了一下错误,但我根本不明白如何在不重新编写程序的整个结构的情况下解决这个错误。

    我的代码非常冗长,但如果需要,我可以提供。

5 个答案:

答案 0 :(得分:2)

最好的方法是重新编写代码,使其不使用UI组件。

完成后,您可以使用ReportProgress / ProgressChanged和RunWorkerCompleted刷新UI。

如果您仍想使用UI组件,可以尝试调用:

this.Invoke(new Action(() => 
    {
        //code that uses UI for instance :
        //this.TextBox1.Text = "test"
    });

答案 1 :(得分:0)

最可能的罪魁祸首是您正在访问后台工作人员控件持有的值。除非有人调用GUI线程,否则不能,也不能。长话短说我尝试从 do work 线程中的文本框中读取值时遇到了同样的问题,即使这是一个读取,它也失败了。 / p>

我建议您从后台工作程序中删除所有数据访问/更新以解决此问题。

以下是我撰写的关于后台工作者的文章

C# WPF: Linq Fails in BackgroundWorker DoWork Event

C# WPF: Threading, Control Updating, Status Bar and Cancel Operations Example All In One

答案 2 :(得分:0)

当您尝试从BackGroundWorker写入窗体上的控件时发生错误。编写控件时需要添加InVoke。请参阅以下网页:https://msdn.microsoft.com/en-us/library/ms171728%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396

答案 3 :(得分:0)

您的代码从创建它们的线程以外的线程访问GUI控件的属性。 WindowsForms / WPF在内部对其进行检查,发现您正在从另一个线程访问控件的属性并引发异常。

我建议你使用MVVM模式。此外,BackgroundWorker现在被认为已经过时,您应该使用带有async / await关键字的Tasks。以下是我在WPF应用程序中的操作方法:

public class ViewModel : INotifyPropertyChanged
{
    ...

    public string PathInfo { ... } // raises INotifyPropertyChanged.PropertyChanged event from the setter
    public RelayCommand ProcessPathsCommand { get; set; }

    public ViewModel()
    {
        ProcessPathsCommand = new RelayCommand(ProcessPaths);
    }

    public async void ProcessPaths()
    {
        // disable the command, which will lead to disabling a button bound to the command
        ProcessPathsCommand.IsEnabled = false;

        try
        {
            // run processing on another thread
            await Task.Run(() =>
            {
                // emulate hard-work
                Thread.Sleep(5000);
                // update the property on the view model, which will lead to updating a textblock bound to this property                
                // in WPF you can update the bound property right from another thread and WPF will automatically dispatch PropertyChanged event to the main UI thread. In WinForms this would lead to an exception.
                PathInfo = "Here are the results: bla bla bla";
            });
            // In WinForms you would need to update the bound property here:
            // Thanks to Tasks and await this line of code will be executed only after the task is finished
            // PathInfo = resultFromTaskThread;
        }
        finally
        {
            ProcessPathsCommand.IsEnabled = true;
        }
    }

我们中的许多人都记得在WindowsForms中我们必须使用Control.Invoke()来从另一个线程更新GUI控件(我们中的许多人仍然在WPF中使用Dispatcher.Invoke,即使它没有必要)。借助WPF,微软最终让我们更轻松! WPF自动将PropertyChanged事件调度到主GUI线程,因此我们可以简单地从另一个线程更新视图模型上的属性(绑定到UI上的某个控件),属性setter将引发PropertyChanged事件,WPF将自动将此事件调度到UI线程!
你也可以在这里阅读:
Multithreading and Dispatching in MVVM Applications

如果您需要更多详细信息,请随时与我们联系。

答案 4 :(得分:0)

如果TB_path或TB_TrackingNum是UI元素(我怀疑它们是),那么您正在尝试访问UI。

如果只是将UI元素绑定到公共属性,则可以从BackgroundWorker访问公共属性。