刷新进度条
Refresh progress bar
我想在 C# WPF 中刷新进度条。
这道题听起来很简单,我应该可以google。但是我看到的解决方案并不令我满意。
假设我必须 运行 一个很长的算法,例如5 个不同的步骤。
我不知道计算不同的步骤需要多长时间。
但我知道我编程了什么,我可以使用分析器来检查 CPU 每个步骤使用了多少时间(以所有步骤总时间的百分比表示)。
这可能是时间,例如:
Method1() takes 3s
Method2() takes 5s
Method3() takes 1s
这是我的方法:
"Easy" 方法:
ProgressBar pb = new ProgressBar()
{
// The total duration of all methods
Maximum = 9
};
Method1();
// + 3 for 3 seconds
pb.Value += TimeForMethod1;
Method2();
// + 5 for 5 seconds
pb.Value += TimeForMethod2;
Method3();
// + 1 for 1 second
pb.Value += TimeForMethod3;
这很简单。但是有一个问题。这会阻塞我的 UI 线程 9 秒,这太可怕了(因为用户可能认为程序崩溃了)。
所以使用线程似乎很明显..
"Thread" 方法:
这有一个问题,我需要调度 ProgressBar 上的每个操作,这可能非常慢(对于 ProgressBar 上的大量更新)
我为此写了一篇"TaskQueue"。我可以在 Queue
中保存我想做的所有工作,并且 Thread
在调用 Run
并更新 ProgressBar
(和 Label
) 在任务之间。
我不想 post ThreadQueue
的所有代码,因为它的实现非常好,也许还不是很好(还)。
这是线程方法的重要部分:
foreach (var threadQueueNode in threadQueue)
{
// Changes e.g. a label displaying what the thread is doing next
threadQueueNode.PreMainFunction.Invoke();
// Executes the main task
this.Result = threadQueueNode.MainFunction.Invoke();
// Updates the ProgressBar after the work is done.
threadQueueNode.PostMainFunction.Invoke();
}
PostMainFunction 是一个 Delegate
,例如这个:
PostMainFunction = (Action<int>)((value) => this.Dispatcher.Invoke(() => this.ProgressBarStatus.Value += value));
对于像我这样的问题,更新 ProgessBar 的专业方法是什么?
我很乐意进行讨论。
感谢您的帮助和宝贵时间!
This has the problem that I need to dispach every operation on the ProgressBar which could be very slow
解决方案是预先计算对进度条的更改,仅调用 UI 线程并在需要时更新图形。
例如,您有 100.000 次操作。您不需要更新进度条 100.000 次。无论如何,用户不会注意到差异。每个百分比更新一次(在本例中为 1000 条记录),因此用户将收到每个百分比的通知。每隔几秒更新一次 UI 就可以了。
BackgroundWorker 清晰易读:
var bw = new BackgroundWorker();
bw.DoWork += (s, e) =>
{
var worker = s as BackgroundWorker;
Method1();
worker.ReportProgress(30);
Method2();
worker.ReportProgress(80);
Method3();
worker.ReportProgress(100);
};
bw.ProgressChanged += (s, e) =>
{
pb.Value += e.ProgressPercentage;
};
bw.RunWorkerCompleted += (s, e) =>
{
};
bw.RunWorkerAsync();
我想在 C# WPF 中刷新进度条。
这道题听起来很简单,我应该可以google。但是我看到的解决方案并不令我满意。
假设我必须 运行 一个很长的算法,例如5 个不同的步骤。 我不知道计算不同的步骤需要多长时间。 但我知道我编程了什么,我可以使用分析器来检查 CPU 每个步骤使用了多少时间(以所有步骤总时间的百分比表示)。
这可能是时间,例如:
Method1() takes 3s
Method2() takes 5s
Method3() takes 1s
这是我的方法:
"Easy" 方法:
ProgressBar pb = new ProgressBar()
{
// The total duration of all methods
Maximum = 9
};
Method1();
// + 3 for 3 seconds
pb.Value += TimeForMethod1;
Method2();
// + 5 for 5 seconds
pb.Value += TimeForMethod2;
Method3();
// + 1 for 1 second
pb.Value += TimeForMethod3;
这很简单。但是有一个问题。这会阻塞我的 UI 线程 9 秒,这太可怕了(因为用户可能认为程序崩溃了)。
所以使用线程似乎很明显..
"Thread" 方法:
这有一个问题,我需要调度 ProgressBar 上的每个操作,这可能非常慢(对于 ProgressBar 上的大量更新)
我为此写了一篇"TaskQueue"。我可以在 Queue
中保存我想做的所有工作,并且 Thread
在调用 Run
并更新 ProgressBar
(和 Label
) 在任务之间。
我不想 post ThreadQueue
的所有代码,因为它的实现非常好,也许还不是很好(还)。
这是线程方法的重要部分:
foreach (var threadQueueNode in threadQueue)
{
// Changes e.g. a label displaying what the thread is doing next
threadQueueNode.PreMainFunction.Invoke();
// Executes the main task
this.Result = threadQueueNode.MainFunction.Invoke();
// Updates the ProgressBar after the work is done.
threadQueueNode.PostMainFunction.Invoke();
}
PostMainFunction 是一个 Delegate
,例如这个:
PostMainFunction = (Action<int>)((value) => this.Dispatcher.Invoke(() => this.ProgressBarStatus.Value += value));
对于像我这样的问题,更新 ProgessBar 的专业方法是什么?
我很乐意进行讨论。
感谢您的帮助和宝贵时间!
This has the problem that I need to dispach every operation on the ProgressBar which could be very slow
解决方案是预先计算对进度条的更改,仅调用 UI 线程并在需要时更新图形。
例如,您有 100.000 次操作。您不需要更新进度条 100.000 次。无论如何,用户不会注意到差异。每个百分比更新一次(在本例中为 1000 条记录),因此用户将收到每个百分比的通知。每隔几秒更新一次 UI 就可以了。
BackgroundWorker 清晰易读:
var bw = new BackgroundWorker();
bw.DoWork += (s, e) =>
{
var worker = s as BackgroundWorker;
Method1();
worker.ReportProgress(30);
Method2();
worker.ReportProgress(80);
Method3();
worker.ReportProgress(100);
};
bw.ProgressChanged += (s, e) =>
{
pb.Value += e.ProgressPercentage;
};
bw.RunWorkerCompleted += (s, e) =>
{
};
bw.RunWorkerAsync();