【发布时间】:2014-03-12 21:16:07
【问题描述】:
嗯,我有以下问题,希望你能帮助我:
我想创建一个带有后台工作程序的 WPF 应用程序,用于更新富文本框和其他 UI 元素。这个后台工作者应该处理一些数据,例如处理文件夹的内容,进行一些解析等等。由于我想将尽可能多的代码移到 Main 类之外,所以我创建了一个名为 MyProcess.cs 的类,如下所示(事实上,到目前为止,这个类没有多大意义,它会填充更多如果此问题已解决,则处理元素)。一般功能应该是:
- MainWindow:将创建一个字符串数组(命名为
this.folderContent) - MainWindow:后台工作人员开始将此数组作为参数
- MainWindow:将调用
DoWork()方法(我知道,这个现在在新线程中运行) - MyProcess:根据给定的字符串数组生成一个(到目前为止未格式化的)段落
- MainWindow:如果后台工作程序完成,则调用
RunWorkerCompleted()方法(在 UI 线程中运行),该方法应通过该方法的返回参数更新 WPF RichTextBox
最后一步会导致 InvalidOperationsException 并带有注释,“调用线程无法访问此对象,因为不同的线程拥有它。”我阅读了一些关于后台工作人员类及其功能的信息。所以我认为这与MyProcess的Execute()方法中的this.formatedFilenames.Inlines.Add(new Run(...))调用有关。如果我将 Paragraph 属性替换为字符串列表或类似内容(无需额外的 new() 调用),我可以通过 get 方法毫无问题地访问该成员。我发现的所有与后台工作者相关的示例都只返回基本类型或简单类。
MainWindow.xaml.cs
public MainWindow()
{
InitializeComponent();
this.process = new MyProcess();
this.worker = new BackgroundWorker();
this.worker.DoWork += worker_DoWork;
this.worker.RunWorkerCompleted += worker_RunWorkerCompleted;
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
this.process.Execute((string[])e.Argument);
e.Result = this.process.Paragraph();
}
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.rtbFolderContent.Document.Blocks.Clear();
// the next line causes InvalidOperationsException:
// The calling thread cannot access this object because a different thread owns it.
this.rtbFolderContent.Document.Blocks.Add((Paragraph)e.Result);
}
...
// folderContent of type string[]
this.worker.RunWorkerAsync(this.folderContent);
...
编辑: 因为这已被问到: RunWorkerAsync 被称为例如在按钮单击事件上或通过对话框选择文件夹之后,因此在 UI 线程中。
MyProcess.cs
class MyProcess
{
Paragraph formatedFilenames;
public MyProcess ()
{
this.formatedFilenames = new Paragraph();
}
public void Execute(string[] folderContent)
{
this.formatedFilenames = new Paragraph();
if (folderContent.Length > 0)
{
for (int f = 0; f < folderContent.Length; ++f)
{
this.formatedFilenames.Inlines.Add(new Run(folderContent[f] + Environment.NewLine));
// some dummy waiting time
Thread.Sleep(500);
}
}
}
public Paragraph Paragraph()
{
return this.formatedFilenames;
}
}
【问题讨论】:
-
+1 为有起始代表和第一个问题的人提供如此布局合理的帖子
-
你在哪里打电话
this.worker.RunWorkerAsync(this.folderContent); -
出于好奇,您的目标是什么版本的 .NET 框架?如果您可以访问 4.5 的新 async/await 功能,这些操作会变得容易得多
-
我正在使用 .NET 4.5,调用 RunWorkerAsync,例如在通过对话框选择目录或向上移动到父文件夹(也通过按钮事件)之后...感谢您的所有 cmets,我明天会尝试并报告。
标签: c# wpf multithreading backgroundworker