简体   繁体   English

(C#) BackgroundWorker() ProgressChanged 不工作

[英](C#) BackgroundWorker() ProgressChanged not working

I have a WPF application that consist of two threads simulating an enterprise producting and selling items in 52 weeks (only one transaction is allowed per week).我有一个WPF应用程序,它由两个线程组成,模拟企业在 52 周内生产和销售商品(每周只允许进行一次交易)。 I need to use a background worker as well so that I can display the data in a listview.我还需要使用后台工作人员,以便我可以在列表视图中显示数据。 As of right now, my UI freezes when clicking on simulate but I can see that the output is still working in the debugging terminal.截至目前,我的 UI 在单击simulate时冻结,但我可以看到输出仍在调试终端中工作。 I have tried everything that I can think of and to be honest, I have had the help of my teacher and even he couldn't find a working solution.我已经尝试了我能想到的所有方法,老实说,我得到了老师的帮助,即使他也找不到可行的解决方案。


  1. What is freezing my UI when I call Simulate() ?当我调用Simulate()时,什么冻结了我的 UI?
  2. When my code is different and my UI isn't freezing, my listview never updates because it seems that DataProgress() doesn't work — e.UserStart is never iterating.当我的代码不同并且我的 UI 没有冻结时,我的列表视图永远不会更新,因为DataProgress()似乎不起作用 - e.UserStart从不迭代。

Simulate button calls :模拟按钮调用:

private void Simulate(object sender, RoutedEventArgs e)
{
    // Declare BackgroundWorker
    Data = new ObservableCollection<Operations>();
    worker = new BackgroundWorker();
    worker.WorkerReportsProgress = true;
    worker.WorkerSupportsCancellation = true;
    worker.RunWorkerAsync(52);

    worker.DoWork += ShowData;
    worker.ProgressChanged += DataProgress;
    worker.RunWorkerCompleted += DataToDB;

    Production = new Production(qtyProduction, timeExecProd);
    Sales = new Sales(qtySales, timeExecSales);

    Thread prod = new Thread(Production.Product);
    prod.Start();

    Thread.Sleep(100);

    Thread sales = new Thread(Sales.Sell);
    sales.Start();
}

DoWork : ShowData() : DoWork : ShowData() :

Console.WriteLine("Simulation started | Initial stock : 500");

Production = new Production(qtyProduction, timeExecProd);
Sales = new Sales(qtySales, timeExecSales);

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);
}

ProgressChanged : DataProgress() : ProgressChanged : DataProgress() :

if (e.UserState != null) // While using debugger, it looks like this is called over & over
{
    Data.Add(new Operations() 
    {
        id = rnd.Next(1,999),
        name = Factory.name,
        qtyStock = Factory.Stock,
        averageStock = Factory.AverageStock,
        week = Factory.Week
    });
    listview.ItemsSource = Data;
}

RunWorkerCompleted : DataToDB() : RunWorkerCompleted : DataToDB() :

    // Outputs "Work done" for now.

In case you want to know what happens when I call my threads, it looks like this :如果你想知道当我调用我的线程时会发生什么,它看起来像这样:

Sell() :卖() :

while (Factory.Week <= 52)
{
    lock (obj)
    {
        // some math function callings¸
        Factory.Week++;
    }
    Thread.Sleep(timeExecSales);
}

Should I use a third thread just for updating my listview?我应该使用第三个线程来更新我的列表视图吗? I don't see how as I need it to be synced with my static variables.我不明白我需要它如何与我的静态变量同步。 This is my first project for learning multithreading... I'm kind of clueless and flabbergasted that even my teacher can't help.这是我学习多线程的第一个项目……我有点不知所措,甚至连我的老师都帮不上忙。

On the one hand, there isnt enough context in the code posted to get a full picture to answer your questions accurately .一方面,发布的代码中没有足够的上下文来全面了解准确回答您的问题。 We can, however, deduce what is going wrong just from the code you have posted.但是,我们可以仅从您发布的代码中推断出问题所在。

First, lets try to answer your two questions.首先,让我们试着回答你的两个问题。 We can likely infer the following:我们大概可以推断出以下几点:

This code here:这段代码在这里:

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;
}

You are using a Windows Forms background thread object to try and update a WPF GUI object which should only be done on the main GUI thread.您正在使用 Windows 窗体后台线程对象来尝试更新 WPF GUI 对象,该对象只能在主 GUI 线程上完成。 There is also the obvious no-no of never updating GUI objects from non-UI threads.还有一个明显的禁忌是永远不要从非 UI 线程更新 GUI 对象。 Using BackgroundWorker also has its own issues with threading (foreground/background), contexts and execution, as it relies on the Dispatcher and SynchronizationContexts to get the job done.使用BackgroundWorker在线程(前台/后台)、上下文和执行方面也有其自身的问题,因为它依赖DispatcherSynchronizationContexts来完成工作。

Then there is the curiosity of setting the binding over and over in this line:然后就是在这一行一遍又一遍地设置绑定的好奇心:

listview.ItemsSource = Data;

Let's put a pin in that for a moment...让我们暂时插上一个别针......

There is, as the other commenter pointer out already, no exit strategy in your while loop:正如其他评论者指出的那样,您的 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);
}

But thats not the bigger problem... in addition to the misuse/misunderstanding of when/how many/how to use threading, there doesnt seem to be any kind of thread synchronization of any kind.但这不是更大的问题......除了滥用/误解何时/多少/如何使用线程之外,似乎没有任何类型的线程同步。 There is no way to predict or track thread execution of lifetime in this way.没有办法以这种方式预测或跟踪生命周期的线程执行。

At this point the question is technically more or less answered, but I feel like this will just leave you more frustrated and no better off than you started.在这一点上,这个问题在技术上或多或少得到了回答,但我觉得这只会让你更加沮丧,并且不会比开始时更好。 So maybe a quick crash course in basic design might help straighten out this mess, something your teacher should have done.因此,也许在基本设计方面的快速速成课程可能有助于解决这个烂摊子,这是您的老师应该做的。

Assuming you are pursuing software development, and since you have chosen WPF here as your "breadboard" so to speak, you will likely come across terms such as MVC (model view controller) or MVVM (model view view-model).假设您正在从事软件开发,并且既然您在这里选择了 WPF 作为您的“面包板”,那么您可能会遇到诸如 MVC(模型视图控制器)或 MVVM(模型视图视图模型)之类的术语。 You will also likely come across design principles such as SOLID, separation of concerns, and grouping things into services.您还可能会遇到设计原则,例如 SOLID、关注点分离和将事物分组到服务中。

Your code here is a perfect example of why all of these frameworks and principles exist.您在此处的代码是所有这些框架和原则存在的完美示例。 Lets look at some of the problems you have encountered and how to fix them:让我们来看看您遇到的一些问题以及如何解决这些问题:

  1. You have threading code (logic and services - controller [loosely speaking]) mixed in with presentation code (listview update - view) and collection update (your observable collection - model).您将线程代码(逻辑和服务 - 控制器 [松散地说])与表示代码(列表视图更新 - 视图)和集合更新(您的可观察集合 - 模型)混合在一起。 Thats one reason (of many) you are having such a difficult time coding, fixing and maintaining the problem at hand.这就是您在编码、修复和维护手头问题时遇到如此困难的原因之一(很多)。 To clean it up, separate it out (separation of concerns).要清理它,请将其分离(关注点分离)。 You might even move each operation into its own class with an interface/API to that class (service/ micro-service).您甚至可以将每个操作移动到它自己的类中,并带有该类的接口/API(服务/微服务)。

  2. Not everything needs to be solved with threads.并不是所有的事情都需要用线程来解决。 But for now, lets learn to crawl, then walk before we run.但是现在,让我们先学会爬行,然后在跑步之前先走路。 Before you start learning about async/await or the TPL (task parallel library) lets go old school.在您开始学习 async/await 或 TPL(任务并行库)之前,让我们回到老学校。 Get a good book... something even from 20 years ago is find... go old school, and learn how to use the ThreadPool and kernel synchronization objects such as mutexes, events, etc and how to signal between threads.买一本好书……即使是 20 年前的东西也能找到……回到老学校,学习如何使用 ThreadPool 和内核同步对象,例如互斥锁、事件等,以及如何在线程之间发出信号。 Once you master that, then learn about TPL and async/await.一旦你掌握了它,然后学习 TPL 和 async/await。

  3. Dont cross the streams.不要越过溪流。 Dont mix WinForms, WPF and I even saw Console.WriteLine .不要混用 WinForms、WPF,我什至看到了Console.WriteLine

  4. Learn about Data Binding, and in particular how it works in WPF.了解数据绑定,特别是它在 WPF 中的工作原理。 ObservableCollection is your friend, bind your ItemsSource to it once , then update the ObservableCollection and leave the GUI object alone. ObservableCollection是您的朋友,将您的ItemsSource绑定到它一次,然后更新ObservableCollection并留下 GUI 对象。

Hopefully this will help you straighten out the code and get things running.希望这将帮助您理顺代码并使事情运行。

Good luck!祝你好运!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 后台工作人员进度更改事件C# - Backgroundworker progresschanged event c# c# backgroundWorker 未引发 ProgressChanged 或 RunWorkerCompleted 事件 - c# backgroundWorker not raising ProgressChanged or RunWorkerCompleted events backgroundWorker_ProgressChanged无法正常工作? - backgroundWorker_ProgressChanged not working? backgroundWorker和progressChanged无法正常工作 - backgroundWorker and progressChanged not working C#BackgroundWorker - 最好将结果保存到文件本身还是使用ProgressChanged? - C# BackgroundWorker - better to save results to a file itself or use ProgressChanged? 在调用ReportProgress之后,不会立即触发C#BackgroundWorker.ProgressChanged - C# BackgroundWorker.ProgressChanged not fired immediately after ReportProgress is called C#BackgroundWorker无法正常工作 - C# BackgroundWorker Not Working C#BackgroundWorker ProgressChanged在函数结束之前不会被解雇 - C# BackgroundWorker ProgressChanged doesn't get fired until end of function 在C#winforms中,为什么UI标签没有更新并跟上backgroundworker progresschanged事件? - In C# winforms, why is the UI label not updating and keeping up with backgroundworker progresschanged event? c#如何使用BackgroundWorker的ProgressChanged事件在线程中间做UI动作 - c# how to use ProgressChanged event of BackgroundWorker to do UI actions in the middle of thread
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM