我有UI WPF应用程序。
可能有人知道为什么这段代码不能工作?
案例1:
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += delegate
{
//some logic
};
worker.RunWorkerAsync();在这种情况下,我得到了异常,调用线程不能访问这个对象,因为另一个线程拥有它。然后我将其更改为:
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += delegate
{
this.Dispatcher.BeginInvoke(
new Action(() => { //my code here }), null);
}; 在此之后,UI在执行此代码期间被冻结。就像它在同一个线程中执行一样
案例2:
BackgroundWorker worker = new BackgroundWorker();
worker.RunWorkerAsync(new Action(() =>
{
//some code here
}));在这种情况下,Action中的代码不会执行。
//----------------------------------UPDATED--------------------------------------//
感谢你们的帮助我的代码不能正常工作的原因在下面提到。我在后台线程中访问了一些UI元素。现在,在调用BackgroundWorker之前,我将从UI元素中获取所有值。现在我声明了新的变量,并从所需的UI元素中为它们赋值,然后将这些变量传递给BackgroundWorker而不是UI元素(这是它最初做的事情)。
发布于 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方法被调用之后,这使对象成为只读的和线程安全的。
发布于 2010-07-25 14:49:45
第二个版本不会执行您想要的操作,因为接受参数的RunWorkerAsync重载的参数只是DoWorkEventArgs.Argument的值。它并不意味着要执行的操作-除非您提供了一个事件处理程序,该处理程序将值转换为Action并调用它。
第一个版本应该可以工作--但根据Oded的评论,你还没有给出任何关于“不工作”的意思。您也没有指定是两个版本都失败了还是只有一个版本失败。
发布于 2010-07-26 02:53:38
另一件需要非常小心的事情是:如果你将DoWork设置为匿名方法,请确保你没有在调用方法中的对象上创建闭包。这些对象位于调用方法的线程上,如果DoWork方法接触到它们,那将是一件坏事。
一个简单的例子:
MyClass foo = new MyClass();
worker.DoWork += delegate
{
foo.MyProperty++;
};我通常很少使用匿名方法。如果您不是有意使用闭包,那么闭包就会产生各种各样的问题。如果你有意使用它们,很容易就会写出太过微妙的代码,以至于一年后都不能修改。编写一个带有显式参数的命名方法可能需要更多的时间和代码,但这并不比记录闭包所做的事情更难。
我在BackgroundWorker中根本不使用匿名方法。不仅存在依赖闭包而没有真正考虑它的所有含义的风险,而且您还很可能编写了无法进行单元测试的代码。
https://stackoverflow.com/questions/3328331
复制相似问题