C# (C) BackgroundWorker()进程已更改,无法工作
我有一个WPF应用程序,它由两个线程组成,模拟企业在52周内生产和销售商品,每周只允许一次交易。我还需要使用后台工作程序,以便在listview中显示数据。现在,我的UI在单击simulate时冻结,但我可以看到输出仍在调试终端中工作。我已经尝试了我能想到的一切,老实说,我得到了老师的帮助,甚至他也找不到有效的解决办法 当我调用Simulate时冻结我的UI是什么? 当我的代码不同并且我的UI没有冻结时,我的listview永远不会更新,因为DataProgress似乎不起作用-e.UserStart永远不会迭代。 模拟按钮调用: 私有void模拟对象发送方,RoutedEventArgs e { //声明BackgroundWorker 数据=新的可观察收集; 工人=新的背景工人; worker.WorkerReportsProgress=true; worker.worker支持扫描单元=true; worker.RunWorkerAsync52; worker.DoWork+=ShowData; worker.ProgressChanged+=数据进度; worker.RunWorkerCompleted+=DataToDB; 生产=新产品QTYProduction,timeExecProd; 销售=新的SalesqtySales,timeExecSales; 螺纹产品=新螺纹产品。产品; 生产启动; 线程100; 线程销售=新线程销售。销售; 销售。启动; } 道工:展示数据: Console.WriteLineSimulation启动|初始库存:500; 生产=新产品QTYProduction,timeExecProd; 销售=新的SalesqtySales,timeExecSales; 而工厂每周C# (C) BackgroundWorker()进程已更改,无法工作,c#,wpf,multithreading,backgroundworker,C#,Wpf,Multithreading,Backgroundworker,我有一个WPF应用程序,它由两个线程组成,模拟企业在52周内生产和销售商品,每周只允许一次交易。我还需要使用后台工作程序,以便在listview中显示数据。现在,我的UI在单击simulate时冻结,但我可以看到输出仍在调试终端中工作。我已经尝试了我能想到的一切,老实说,我得到了老师的帮助,甚至他也找不到有效的解决办法 当我调用Simulate时冻结我的UI是什么? 当我的代码不同并且我的UI没有冻结时,我的listview永远不会更新,因为DataProgress似乎不起作用-e.UserSt
虽然Factory.Week一方面,在发布的代码中没有足够的上下文来完整地回答您的问题。然而,我们可以从您发布的代码中推断出哪里出了问题 首先,让我们试着回答你的两个问题。我们可能会推断出以下情况: 此代码如下:
if (e.UserState != null)
{
Data.Add(new Operations()
{
id = rnd.Next(1,999),
name = Factory.name,
qtyStock = Factory.Stock,
averageStock = Factory.AverageStock,
week = Factory.Week
});
listview.ItemsSource = Data;
}
您正在使用Windows窗体后台线程对象来尝试和更新WPF GUI对象,该对象应仅在主GUI线程上完成。还有一个明显的问题,就是永远不要从非UI线程更新GUI对象。使用BackgroundWorker在前台/后台线程、上下文和执行方面也有自己的问题,因为它依赖Dispatcher和SynchronizationContext来完成任务
然后在这一行中反复设置绑定是一种好奇:
listview.ItemsSource=数据
让我们在里面插一根别针一会儿
正如另一位评论者已经指出的,while循环中没有退出策略:
while (Factory.Week < max) // max = 52
{
if (worker.CancellationPending) // also this isn't reacting to worker.CancelAsync();
e.Cancel = true;
// My teacher tried to call my threads from here, but it breaks the purpose of having
// two threads as he was just calling 52 times two functions back to back and therefore
// wasn't "randomizing" the transactions.
int progressPercentage = Convert.ToInt32(((double)(Factory.Week) / max) * 100);
(sender as BackgroundWorker).ReportProgress(progressPercentage, Factory.Week);
}
但这不是更大的问题。。。除了误用/误解何时/多少/如何使用线程之外,似乎没有任何类型的线程同步。用这种方法无法预测或跟踪生命周期的线程执行
在这一点上,这个问题在技术上或多或少得到了回答,但我觉得这只会让你更加沮丧,也不会比你开始时更好。所以,也许一个基础设计速成班可以帮助你理顺这个烂摊子,这是你的老师应该做的
假设您正在进行软件开发,并且既然您在这里选择了WPF作为您的试验板,那么您可能会遇到诸如MVC模型视图控制器或MVVM模型视图模型之类的术语。您还可能会遇到设计原则,如固体、关注点分离和将事物分组到服务中
这里的代码是所有这些框架和原则存在的完美例子。让我们看看您遇到的一些问题以及如何解决这些问题:
线程代码逻辑和服务-控制器[粗略地说]与表示代码listview更新-view和collection更新混合在一起
ble集合-模型。这就是为什么您在编码、修复和维护手头的问题时遇到如此困难的原因之一。要清理它,请将其与关注点分离。您甚至可以将每个操作移动到自己的类中,并使用该类服务/微服务的接口/API
并非所有问题都需要用线程来解决。但现在,让我们先学爬,然后在跑之前先走路。在您开始学习async/await或TPL任务并行库之前,让我们先从老一套做起。得到一本好书。。。20年前的一些东西被发现了。。。走老路,学习如何使用线程池和内核同步对象,如互斥体、事件等,以及如何在线程之间发送信号。一旦掌握了这一点,就可以学习TPL和async/await
不要越过小溪。不要混合使用WinForms、WPF和我甚至看到了Console.WriteLine
了解数据绑定,特别是它如何在WPF中工作。ObservaleCollection是您的朋友,将您的ItemsSource绑定到它一次,然后更新ObservaleCollection并让GUI对象单独使用
希望这将帮助您理顺代码并使其运行
祝你好运 如前所述,while循环从未终止。它以非常高的速率猛击UI线程,每秒数百万次。这也是非常昂贵的代码,它使UI线程消耗100%的核心,永远无法赶上。其副作用是,它不再能够承担起正常的职责,重新粉刷窗口并响应输入。考虑到这是多么错误,最好采取激烈的行动。而是在DoWork中生成一个结果列表,并使用RunWorkerCompleted更新ItemsSource。只需查看代码,不要在连接所有事件之前告诉后台工作人员开始运行。此外,仅更改控件上的ItemSource不会强制刷新。至少,您应该在listview上调用DataBind,并可能调用refresh/repaint。。将while Factory.Week