【发布时间】:2020-05-30 13:16:49
【问题描述】:
我有一个 WPF 应用程序,它由两个线程组成,模拟企业在 52 周内生产和销售商品(每周只允许进行一次交易)。我还需要使用后台工作人员,以便可以在列表视图中显示数据。截至目前,我的 UI 在单击 simulate 时冻结,但我可以看到输出仍在调试终端中工作。我已经尝试了所有我能想到的方法,老实说,我得到了老师的帮助,甚至他也找不到有效的解决方案。
- 当我调用
Simulate()时,我的 UI 冻结是什么原因? - 当我的代码不同并且我的 UI 没有冻结时,我的列表视图永远不会更新,因为
DataProgress()似乎不起作用 -e.UserStart永远不会迭代。
模拟按钮调用:
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() :
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() :
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() :
// Outputs "Work done" for now.
如果你想知道当我调用我的线程时会发生什么,它看起来像这样:
卖出():
while (Factory.Week <= 52)
{
lock (obj)
{
// some math function callings¸
Factory.Week++;
}
Thread.Sleep(timeExecSales);
}
我应该使用第三个线程来更新我的列表视图吗?我看不出我需要如何将它与我的静态变量同步。 这是我学习多线程的第一个项目......我有点无能为力,甚至我的老师都帮不上忙。
【问题讨论】:
-
正如发布的那样,while 循环永远不会终止。它以非常高的速度猛击 UI 线程,每秒数百万次。这也是非常昂贵的代码,它使 UI 线程消耗 100% 核心并且永远无法赶上。副作用是它不再执行其正常职责,重新绘制窗口并响应输入。鉴于这是多么错误,最好变得激烈。而是在 DoWork 中生成结果列表并使用 RunWorkerCompleted 更新 ItemsSource。
-
只看你的代码,在你钩住所有事件之前不要告诉后台工作人员开始运行。此外,仅更改控件上的 ItemSource 不会强制它刷新。至少,您可能应该在列表视图上调用 DataBind,并可能调用刷新/重绘。
-
正如 stacy 所说.. 将
while (Factory.Week < max)更改为while (Factory.Week < max && !worker.CancellationPending) -
尽管有其他问题,您应该为此使用任务。我最喜欢的编程名言之一来自 Stephen Cleary 的“C# Cookbook 中的并发”:“只要你输入 new Thread(),就结束了;你的项目已经有遗留代码了。”
标签: c# wpf multithreading backgroundworker