首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >BackgroundWorker问题

BackgroundWorker问题
EN

Stack Overflow用户
提问于 2010-07-25 14:45:24
回答 3查看 1.3K关注 0票数 1

我有UI WPF应用程序。

可能有人知道为什么这段代码不能工作?

案例1:

代码语言:javascript
运行
复制
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += delegate
{
   //some logic
};

worker.RunWorkerAsync();

在这种情况下,我得到了异常,调用线程不能访问这个对象,因为另一个线程拥有它。然后我将其更改为:

代码语言:javascript
运行
复制
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += delegate 
{ 
  this.Dispatcher.BeginInvoke(
    new Action(() =>  { //my code here }), null); 
}; 

在此之后,UI在执行此代码期间被冻结。就像它在同一个线程中执行一样

案例2:

代码语言:javascript
运行
复制
BackgroundWorker worker = new BackgroundWorker();
worker.RunWorkerAsync(new Action(() =>
{
 //some code here
}));

在这种情况下,Action中的代码不会执行。

//----------------------------------UPDATED--------------------------------------//

感谢你们的帮助我的代码不能正常工作的原因在下面提到。我在后台线程中访问了一些UI元素。现在,在调用BackgroundWorker之前,我将从UI元素中获取所有值。现在我声明了新的变量,并从所需的UI元素中为它们赋值,然后将这些变量传递给BackgroundWorker而不是UI元素(这是它最初做的事情)。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2010-07-25 21:10:50

第一个版本的问题是,在“某些逻辑”中,您可能正在访问WPF对象-您不能这样做,WPF对象只能从创建它们的同一线程访问。

第二个版本的问题是,你正在启动一个后台线程,它要求主线程做所有的工作,然后退出,所以你在主线程上做所有的工作(它也做所有的UI工作),UI冻结,本质上这相当于根本不使用BackgroundWorker。

第三个版本,正如Jon Skeet所说,是简单的不正确的用法,不应该像你想象的那样工作。

那么,你需要做什么呢?

在启动后台工作线程之前,您需要从主线程中的UI收集所有信息,您只能使用简单类型(string、int、double等)。和线程安全的类/结构,则不能在BackgroundWorker执行的代码中使用任何WPF类。

收集完所有可以调用RunWorkerAsync的数据后,在DoWork处理程序中,您不能从UI读取数据-您只能访问之前准备的数据,也不能写入UI -您必须将其保存到其他地方(例如,类成员),并在BackgroundWorker完成后将其复制到UI中。

“不能从另一个线程访问WPF”规则的唯一例外是Freezable (以及从freezable继承的所有类)在Freeze方法被调用之后,这使对象成为只读的和线程安全的。

票数 1
EN

Stack Overflow用户

发布于 2010-07-25 14:49:45

第二个版本不会执行您想要的操作,因为接受参数的RunWorkerAsync重载的参数只是DoWorkEventArgs.Argument的值。它并不意味着要执行的操作-除非您提供了一个事件处理程序,该处理程序将值转换为Action并调用它。

第一个版本应该可以工作--但根据Oded的评论,你还没有给出任何关于“不工作”的意思。您也没有指定是两个版本都失败了还是只有一个版本失败。

票数 1
EN

Stack Overflow用户

发布于 2010-07-26 02:53:38

另一件需要非常小心的事情是:如果你将DoWork设置为匿名方法,请确保你没有在调用方法中的对象上创建闭包。这些对象位于调用方法的线程上,如果DoWork方法接触到它们,那将是一件坏事。

一个简单的例子:

代码语言:javascript
运行
复制
MyClass foo = new MyClass();
worker.DoWork += delegate
{
   foo.MyProperty++;
};

我通常很少使用匿名方法。如果您不是有意使用闭包,那么闭包就会产生各种各样的问题。如果你有意使用它们,很容易就会写出太过微妙的代码,以至于一年后都不能修改。编写一个带有显式参数的命名方法可能需要更多的时间和代码,但这并不比记录闭包所做的事情更难。

我在BackgroundWorker中根本不使用匿名方法。不仅存在依赖闭包而没有真正考虑它的所有含义的风险,而且您还很可能编写了无法进行单元测试的代码。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3328331

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档