BackgroundWorker:Argument-Object 的子代
Posted
技术标签:
【中文标题】BackgroundWorker:Argument-Object 的子代【英文标题】:BackgroundWorker: Childs of Argument-Object 【发布时间】:2021-02-12 19:11:18 【问题描述】:我正在开发一个运行平稳的 WPF 应用程序,直到我添加了线程。我想通过将其放入 BackgroundWorker
来简化保存/自动保存过程,这样我的 UI 在保存时不会被阻塞。
将我的应用程序视为自定义相册制作器。
假设我的 UI 由几个图像对象组成。这些图像的来源位于自定义PhotobookImageObject
中,因为每个选定的图像还包含其他元数据。
PhotobookImageObject
public class PhotobookImageObject
public BitmapSource source get; set;
public String unimportantMetadata get; set;
当我想保存时,我想保存完整的相册。为简单起见:
相册
public class Photobook: INotifyPropertyChanged
public List<PhotobookImageObject> Photos get; set;
public String otherMetaData get; set;
我的保存过程在不使用线程时有效。但自从我在BackgroundWorker
中运行它之后,我无法再在list
中访问PhotobookImageObjects
。
现在我知道用于保存的线程无法访问来自不同线程的对象。这就是为什么我使用自定义类将对象推送到 BackgroundWorker 的线程中。我在这里找到了这个解决方案:How do you pass a List<> of Lists<> to a background worker?
这是实际代码:
设置工作器:
private static BackgroundWorker saveWorker = new BackgroundWorker();
private static void saveWorkerExec(Photobook book, String Location, bool notAuto)
saveWorker.DoWork += doWork;
saveWorker.WorkerSupportsCancellation = true;
saveWorker.RunWorkerCompleted += (s, o) =>
Helper.Message("Photobook saved");
if (o.Error != null)
MessageBox.Show("There was an error while saving! \n\n" + o.Error.ToString());
;
BGObj obj = new BGObj
bk = book,
Loc = Location,
not = notAuto
;
saveWorker.RunWorkerAsync(obj);
我用来传输数据的自定义类:
public class BGObj
public Photobook bk get; set;
public String Loc get; set;
public bool not get; set;
BackgroundWorker
应该将类接收到他自己的线程中的实际部分:
private static void doWork(object sender, DoWorkEventArgs e)
BGObj received = e.Argument as BGObj;
Photobook book= received.bk;
String Location = received.Loc;
bool notAuto = received.not;
//this function can not Access the books.Photos.last().source for example.
SaveProjectToContainer(book, Location, notAuto);
当我尝试访问Photos
中Photos
列表中的BitmapSource
时,我仍然收到System.InvalidOperationException
Photobook
。
我的假设:我正在创建的 BGobj
只是引用实际的 Photobook,因此其成员的数据仍然存在于错误的线程中。我到底如何才能确保我的对象的所有子成员实际上都传递给我想要处理它们的线程?还是我在这里错了,还有其他什么?
感谢您的宝贵时间。
【问题讨论】:
当使用BackgroundWorker
(顺便说一句在技术上已经过时,被Task.Run
和async/await 取代)时,您应该在RunWorkerCompleted
事件的处理程序中更新UI。你试过这种方法吗?
我没有更新 UI 中的任何内容。我想将所有必需的对象传递给 backgroundWorker,然后我将所有信息序列化并保存到文件中。任何时候都不需要回调 UI。
好的。但是您仍然需要返回 UI 线程才能访问BitmapSource
对象。 RunWorkerCompleted
事件在 UI 线程上运行,因此您可以利用它。
【参考方案1】:
由于没有人可以帮助我解决这个问题,我遵循 Theodors 的方法并使用 Async/Await
切换到更现代的方法。
据我了解,这并不是让动作在后台运行,而是在线程有可用容量时释放 UI 线程并在“中间”运行 await
" 任务。这允许我访问 UI 元素和在自动保存时仍然会停止应用程序冻结。
如果有人需要一些提示如何解决这个问题,可以这样想:
public static void NotMain()
// queue following function. void Main for example would continue running after this.
await do_stuff_in_between(var object);
// Stuff after await will only happen if the function is done but UI is not blocked
Console.WriteLine("saving done");
public static async Task do_stuff_in_between(var object)
// do stuff with object or whatever you want.
【讨论】:
以上是关于BackgroundWorker:Argument-Object 的子代的主要内容,如果未能解决你的问题,请参考以下文章
将值从 BackgroundWorker DoWork 传递到 BackgroundWorker Completed
C# BackGroundWorker backgroundWorker1_DoWork中,按钮不能按的问题