首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >用于更新进度条的专用C#类

用于更新进度条的专用C#类
EN

Stack Overflow用户
提问于 2013-07-29 13:40:32
回答 4查看 651关注 0票数 0

我想创建一个专用的类来更新我的应用程序中的进度条(在本例中是WPF进度条)。我做了这样的事:

代码语言:javascript
运行
复制
public class ProgressBarUpdate : IDisposable
{
    private readonly double _delta;
    private int _current;
    private int _total;
    private readonly ProgressBar _pb;

    public ProgressBarUpdate(ProgressBar pb, int total)
    {
        _pb = pb;
        _total = total;
        // the pb.Maximum is a double so it doesn`t get truncated
        _delta = _pb.Maximum / total; 
        _current = 0;
        _pb.Visibility = Visibility.Visible;

    }
    public void Dispose()
    {
        _pb.Visibility = Visibility.Collapsed;
        _current = 0;
    }
    public void UpdateProgress()
    {
        _pb.Value =(int)_delta * (++_current);
    }

(在UI线程中):

代码语言:javascript
运行
复制
using (var pu = new ProgressBarUpdate(pb, totalCount)
{
  for (x=0; x<totalCount; x++)
  {
     // operations here 
     pu.UpdateProgress()
  }
}

但是UI可能被阻止了,但没有正确地更新。什么是显示所有进展的最佳方式?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2013-07-29 21:16:04

Winforms/WPF程序是一个Eventing系统。只有一个线程连续地处理事件队列中的事件。这是它的主要工作,理想的是,这是它应该做的唯一的事情。任何类型的UI活动都会在事件队列中生成事件--就像您将鼠标移到窗口上,或者单击某个或某些其他窗口重叠您的窗口,然后当它离开重叠位置时再次发生。所有这些事件都由UI线程处理,这使UI始终保持更新。

此外,Winforms/WPF只允许在UI线程上访问和/或更新控件及其属性,从而以线程安全的方式进行访问。

如果阻止此UI线程或在其上执行其他CPU绑定计算,则您的UI响应性和更新的行为将受到影响。最坏的情况下UI会冻结。

因此,正确的答案是对另一个工作线程执行计算循环,并且只通过使用Dispatcher封送对UI线程的调用来更新进度条UI。

然而,为了回答你的问题和满足你的调查,这里有一些是可能的--但这是坏实践,您应该永远不要做以下事情

简单地说,当您更新进度条的Value属性时,它会使进度条UI失效-所以UI必须更新。因此,假设在事件队列中生成了一个事件,这将导致一些代码运行,从而更新UI。但是,您正在UI线程上运行一个循环--因此,除非您的循环结束,否则线程没有机会处理此事件。因此,您看不到任何UI更新。诀窍是在对进度条的Value进行下一次更新之前,让UI线程处理该事件。您可以通过在事件队列中强制调用一个较低优先级的项来做到这一点--以便在进入下一次迭代之前处理正常和更高优先级的项。

代码语言:javascript
运行
复制
using (var pu = new ProgressBarUpdate(pb, totalCount))
{
  for (int x = 0; x < totalCount ; x++)
  {
     // operations here 
     pu.UpdateProgress();

     Dispatcher.Invoke(DispatcherPriority.Background, new Action(()=>{}));
  }
}
票数 1
EN

Stack Overflow用户

发布于 2013-07-29 15:08:33

如果在UI线程上执行工作并调用UpdateProgress,则在完成工作之前它不会更新,并且UI线程还可以执行其他工作(比如刷新UI)。所以这是行不通的。

如果在后台线程上工作,则需要使用Dispatcher将设置值封送到UI线程。

下面是来自http://tech.pro/tutorial/800/working-with-the-wpf-dispatcher的一个例子

代码语言:javascript
运行
复制
if (!myCheckBox.Dispatcher.CheckAccess())
{
  myCheckBox.Dispatcher.Invoke(
    System.Windows.Threading.DispatcherPriority.Normal,
    new Action(
      delegate()
      {
        myCheckBox.IsChecked = true;
      }
  ));
}
else
{
  myCheckBox.IsChecked = true;
}
票数 0
EN

Stack Overflow用户

发布于 2013-07-29 17:18:04

试试这个:

代码语言:javascript
运行
复制
public ProgressBarUpdate(ProgressBar pb, int total)
{
    _pb = pb;
    _total = total;
    _delta = _pb.MaxValue/((double)total);  /make sure you do not truncate delta
    _current = 0;
    _pb.Visibility = Visibility.Visible;

}
public void Dispose()
{
    _pb.Visibility = Visibility.Collapsed;
    _current = 0;
}
public void UpdateProgress()
{
    _pb.Value = (int)( _delta * (++_current)); //update after the increment
}

我建议也使用float而不是double

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17925632

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档