繁体   English   中英

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

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

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

  1. 抓取目录中的所有文件路径(文件采用指定的命名约定)
  2. 使用分隔符解析文件路径
  3. 输出具有指定格式的文本文件。

问题在于某些目录是数百个演出,它们冻结了表单用户界面,直到完成该过程为止。 我已经阅读了一些有关背景工作者的文章,据我所知,代码中数据密集型部分位于DoWork方法下。 但是,当我尝试将代码实现到DoWork方法中时,遇到了“跨线程操作无效:”错误。 我查找了该错误,但是我根本不了解如何在不重新设计程序整个结构的情况下解决该错误。

我的代码很长,但是我可以根据需要提供。

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

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

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

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

造成这种情况的最可能原因是您正在从后台工作人员访问控件所拥有的值。 除非一个调用返回到GUI线程,否则就无法从这些对象进行写入读取 长话短说,当我尝试从我的工作线程中读取文本框的值时遇到了同样的问题,尽管它是读取的,但失败了。

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

这是我写的有关后台工作者的文章

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

C#WPF:线程,控件更新,状态栏和取消操作示例全部合而为一

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

您的代码从线程创建对象之外的线程访问GUI控件的属性。 WindowsForms / WPF在内部进行检查,查看您是否正在从另一个线程访问控件的属性并引发异常。

我建议您使用MVVM模式。 另外,BackgroundWorker现在被认为已过时,您应该将Tasks与async / await关键字一起使用。 这是我在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,Microsoft终于使我们更容易了! WPF自动将PropertyChanged事件调度到主GUI线程,因此我们可以简单地从另一个线程更新视图模型上的属性(绑定到UI上的某些控件),属性设置器将引发PropertyChanged事件,WPF将自动将此事件调度到UI线程!
您还可以在这里阅读有关此内容:
MVVM应用程序中的多线程和分派

如果您需要更多详细信息,请随时告诉我。

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

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

暂无
暂无

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM