如何增加进度条?
How to increase a progress bar?
这个问题似乎是一个常规问题,但事实并非如此。
无论我在做什么,进度条就是不增加。
在基本概念中,我有一个 GUI 表单,它有一个 bacgroundworker。在 backgroundworker 中,我使用自定义 class 从测量文件中读取数据。我想在完成一个文件后增加进度条,但是无论我做什么它都没有。
我试过:
worker.ReportProgress
方法
Controls.Invoke((MethodInvoker)delegate{});
方法
Furhtermore 也尝试了 Control.Update()
和 Control.Refress()
,但这些都不起作用。
请帮忙!
提前谢谢大家!
进度条不更新的原因是 UI 无法从后台线程更新。 Backgroundworker 在后台线程上运行,使 UI 保持响应。
三种解决方案:
- 在 backgroundworker 中,启动一个在主 UI 线程上运行的新任务,并在那里更新进度条。这是糟糕的编码,但还有其他用例,其中 .InvokeRequired 是有效的。
- 使用 backgroundworker ReportProgress。在 ProgressChanged 处理程序(在 UI 线程上运行)中,正常更新进度条。
- 重写您的应用程序以使用“await Function1()/ async Task Fuction1() 模式而不是 Backgroundworker。这里可能会使用 .InvokeRequired。您还可以使用 EventHandlers return 响应调用者.
示例如下
#1 警告错误的编码风格!
private void bgw1_DoWork(Object sender, DoWorkEventArgs e)
{
...
await Task.Run( () =>
{
progressBar1.InvokeIfRequired( o =>
{
progressBar1.Value += 1;
} );
});
...
}
public static class MyExtensions
{
public static void InvokeIfRequired<T>(this T obj, InvokeIfRequiredDelegate<T> action) where T : ISynchronizeInvoke
{
if (obj.InvokeRequired)
{
obj.Invoke(action, new Object[] { obj });
}
else
{
action(obj);
}
}
}
#2 这种方式效果很好:
private void bgw1_DoWork(Object sender, DoWorkEventArgs e)
{
...
worker.ReportProgress(0, 50); //50% progress out of 100
...
}
private void bgw1_ProgressChanged(Object sender, ProgressChangedEventArgs e)
{
if(e.UserState is Int32 i)
{
progressBar1.Value = i;
}
}
#3
Is a complete re-write and likely outside the scope of your question.
如果对您有帮助,记得标记为答案。
这个问题似乎是一个常规问题,但事实并非如此。
无论我在做什么,进度条就是不增加。
在基本概念中,我有一个 GUI 表单,它有一个 bacgroundworker。在 backgroundworker 中,我使用自定义 class 从测量文件中读取数据。我想在完成一个文件后增加进度条,但是无论我做什么它都没有。
我试过:
worker.ReportProgress
方法
Controls.Invoke((MethodInvoker)delegate{});
方法
Furhtermore 也尝试了 Control.Update()
和 Control.Refress()
,但这些都不起作用。
请帮忙!
提前谢谢大家!
进度条不更新的原因是 UI 无法从后台线程更新。 Backgroundworker 在后台线程上运行,使 UI 保持响应。
三种解决方案:
- 在 backgroundworker 中,启动一个在主 UI 线程上运行的新任务,并在那里更新进度条。这是糟糕的编码,但还有其他用例,其中 .InvokeRequired 是有效的。
- 使用 backgroundworker ReportProgress。在 ProgressChanged 处理程序(在 UI 线程上运行)中,正常更新进度条。
- 重写您的应用程序以使用“await Function1()/ async Task Fuction1() 模式而不是 Backgroundworker。这里可能会使用 .InvokeRequired。您还可以使用 EventHandlers return 响应调用者.
示例如下
#1 警告错误的编码风格!
private void bgw1_DoWork(Object sender, DoWorkEventArgs e)
{
...
await Task.Run( () =>
{
progressBar1.InvokeIfRequired( o =>
{
progressBar1.Value += 1;
} );
});
...
}
public static class MyExtensions
{
public static void InvokeIfRequired<T>(this T obj, InvokeIfRequiredDelegate<T> action) where T : ISynchronizeInvoke
{
if (obj.InvokeRequired)
{
obj.Invoke(action, new Object[] { obj });
}
else
{
action(obj);
}
}
}
#2 这种方式效果很好:
private void bgw1_DoWork(Object sender, DoWorkEventArgs e)
{
...
worker.ReportProgress(0, 50); //50% progress out of 100
...
}
private void bgw1_ProgressChanged(Object sender, ProgressChangedEventArgs e)
{
if(e.UserState is Int32 i)
{
progressBar1.Value = i;
}
}
#3
Is a complete re-write and likely outside the scope of your question.
如果对您有帮助,记得标记为答案。