简体   繁体   English

如何将我的代码适合后台工作人员?

[英]How can I fit my code into a Background Worker?

I've built out a form that does the following: 我建立了一个执行以下操作的表单:

  1. Grabs all the file paths in a directory (files are in a specified naming convention) 抓取目录中的所有文件路径(文件采用指定的命名约定)
  2. Parses file paths using a delimiter 使用分隔符解析文件路径
  3. Outputs a text file with a specified format. 输出具有指定格式的文本文件。

The issue is that some directories are hundreds of gigs which freezes the form UI until the process is done. 问题在于某些目录是数百个演出,它们冻结了表单用户界面,直到完成该过程为止。 I've done some reading on Background workers and to my understanding, the data intensive part of your code goes under the DoWork method. 我已经阅读了一些有关背景工作者的文章,据我所知,代码中数据密集型部分位于DoWork方法下。 However when I try implementing my code into the DoWork method I run into the "Cross-thread operation not valid:" error. 但是,当我尝试将代码实现到DoWork方法中时,遇到了“跨线程操作无效:”错误。 I looked up the error but I simply don't understand how I can work around this error without reworking the entire structure of my program. 我查找了该错误,但是我根本不了解如何在不重新设计程序整个结构的情况下解决该错误。

My code is quite lengthy but I can supply if needed. 我的代码很长,但是我可以根据需要提供。

The best way is to rework your code so it doesn't use UI components. 最好的方法是重新编写代码,使其不使用UI组件。

Once it's done you can use ReportProgress/ProgressChanged and RunWorkerCompleted to refresh the UI. 完成后,您可以使用ReportProgress / ProgressChanged和RunWorkerCompleted刷新UI。

If you still want to use UI components, you may try Invoke : 如果您仍然想使用UI组件,则可以尝试Invoke:

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

The most likely culprit is that you are accessing values held by controls from your background worker. 造成这种情况的最可能原因是您正在从后台工作人员访问控件所拥有的值。 One can neither write , nor read , from those objects unless one invoke's back to the GUI thread. 除非一个调用返回到GUI线程,否则就无法从这些对象进行写入读取 Long story short I ran into the same issue when trying to read a value from a textbox from my do work thread which, even though it was a read, it failed. 长话短说,当我尝试从我的工作线程中读取文本框的值时遇到了同样的问题,尽管它是读取的,但失败了。

I recommend you remove all data access/update from the background worker to resolve this problem. 我建议您从后台工作进程中删除所有数据访问/更新,以解决此问题。

Here is the articles I wrote about the background worker 这是我写的有关后台工作者的文章

C# WPF: Linq Fails in BackgroundWorker DoWork Event C#WPF:Linq在BackgroundWorker DoWork事件中失败

C# WPF: Threading, Control Updating, Status Bar and Cancel Operations Example All In One C#WPF:线程,控件更新,状态栏和取消操作示例全部合而为一

The error is occuring when you are trying to write to a control on the form from the BackGroundWorker. 当您尝试从BackGroundWorker写入窗体上的控件时发生错误。 You need to add InVoke when you write the control. 编写控件时,您需要添加InVoke。 See following webpage : https://msdn.microsoft.com/en-us/library/ms171728%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396 请参阅以下网页: https : //msdn.microsoft.com/zh-cn/library/ms171728%28v=vs.85%29.aspx? f = 255 & MSPPError =-2147217396

Your code accesses properties of GUI controls from the thread other than the one they are created on. 您的代码从线程创建对象之外的线程访问GUI控件的属性。 WindowsForms/WPF internally checks it, sees that you are accessing control's property from another thread and throws an exception. WindowsForms / WPF在内部进行检查,查看您是否正在从另一个线程访问控件的属性并引发异常。

I would advise you to use the MVVM pattern. 我建议您使用MVVM模式。 Also, BackgroundWorker is considered obsolete now and you should use Tasks with async/await keywords instead. 另外,BackgroundWorker现在被认为已过时,您应该将Tasks与async / await关键字一起使用。 Here is how I would do it in a WPF application: 这是我在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;
        }
    }

Many of us remember that in WindowsForms we had to use Control.Invoke() to update GUI controls from another thread (and many of us still use Dispatcher.Invoke in WPF even when it's not necessary). 我们中的许多人都记得在WindowsForms中,我们必须使用Control.Invoke()从另一个线程更新GUI控件(即使不需要,我们中的许多人仍然在WPF中使用Dispatcher.Invoke)。 With WPF Microsoft finally made it easier for us! 有了WPF,Microsoft终于使我们更容易了! WPF automatically dispatches PropertyChanged events to the main GUI thread, so can we simply update a property (bound to some control on UI) on a view model from another thread, the property setter will raise PropertyChanged event, and WPF will automatically dispatch this event to the UI thread! WPF自动将PropertyChanged事件调度到主GUI线程,因此我们可以简单地从另一个线程更新视图模型上的属性(绑定到UI上的某些控件),属性设置器将引发PropertyChanged事件,WPF将自动将此事件调度到UI线程!
You can also read about this here: 您还可以在这里阅读有关此内容:
Multithreading and Dispatching in MVVM Applications MVVM应用程序中的多线程和分派

Feel free to let me know if you need more details. 如果您需要更多详细信息,请随时告诉我。

If TB_path or TB_TrackingNum are UI elements (and I suspect they are) then you are trying to access the UI. 如果TB_path或TB_TrackingNum是UI元素(我怀疑是),那么您正在尝试访问UI。

If you just bind the UI elements to public properties you can access the public properties from the BackgroundWorker. 如果仅将UI元素绑定到公共属性,则可以从BackgroundWorker访问公共属性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用后台工作程序(或任何其他解决方案)停止冻结GUI? - How can I use background worker(or any other solution) to stop freezing my GUI? 我将如何使用Background Worker来使GUI响应? - How would I use Background Worker to get my GUI to respond? 我可以检测我的代码是否在 Azure 辅助角色中执行吗? - Can I detect if my code is executing in an Azure worker role? 如何使用后台工作程序将参数(字符串)发送到UI线程? - How can I send arguments(string) to the UI thread with the Background Worker? 如何更改我的代码以使用后台工作者而不是后台线程 - How can I change my code to use background workers instead of background threads 我无法弄清楚为什么与后台工作程序一起使用时此代码会失败 - I can't figure out why this code is failing when used with a background worker 我的后台工作人员完成后,我想更改表单上的标签。 我应该在哪里添加此代码? - After my background worker is complete, I want to change labels on my form. Where should I add this code? 在后台工作程序中运行代码 - Run code in Background Worker 如何为后台工作人员传递功能? - How do I pass a function for background worker? 代码滞后于UI,但我不清楚如何在需要输入的任务上使用后台工作程序 - Code lags UI but I am unclear how to use Background worker on a task that requires inputs
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM