C#进度条未正确更新

时间:2015-06-12 17:50:16

标签: c# .net progress-bar

我在C#中有一个小程序,它重命名并调整给定目录中的所有图片的大小。

问题是,即使每个文件都在一个循环中处理,并且ProgressBar.Increment(1)在这个循环的末尾,它仍然会在加载时跳过一些数字,就像它的异步一样。我不希望这样,我希望它平滑,并准确显示它是什么文件,没有任何滞后或延迟。 可能有什么不对?

private void renameAndResizeFiles() {
        string[] fileEntries = Directory.GetFiles(directory);
        int filesNumber = fileEntries.Length;
        progressBar.Maximum = filesNumber;
        int i = 1;
        foreach (string oldFileNamePath in fileEntries) {
            // handle file work
            i++;
            updateProgressBar(filesNumber, i);
        }
        progressBar.Refresh();
        progressBar.Value = 0;
    }

    private void updateProgressBar(int filesNumber, int i) {
        progressBar.Refresh();
        progressBar.CreateGraphics().DrawString(i + " / " + filesNumber, 
            new Font("Arial", (float) 10.0, FontStyle.Regular), 
            Brushes.Black, 
            new PointF(progressBar.Width / 2 - 10, progressBar.Height / 2 - 7));
        progressBar.Increment(1);
    }

另外,这是在进度条上显示文字的最佳方式吗?

3 个答案:

答案 0 :(得分:3)

关于进度条上的文字,取决于您是否使用WinForms或WPF。如果是WPF,我真的会考虑在xaml中布局某种网格,在这里你将TextBlock分层放在进度条的一部分上,然后使用DependencyProperties更新它们。对WinForms不太确定,但可能不是.CreateGraphics()。DrawString(),你现在可能更好地获得ProgressBar和TextBlock控件并直接更新它们。

至于顺利更新,可能是因为您没有最短的更新时间,而某些更新可能会如此之快,以至于它似乎“跳过”了。就在他们身边。为确保您看到每个进度条步骤,请尝试在更新进度条方法中的某处插入Thread.Sleep(50)

答案 1 :(得分:1)

为什么不尝试继承ProgressBar课程并自行绘制内容?
假设您正在使用Winforms,以下是一个示例:

using System;
using System.Drawing;
using System.Windows.Forms;

namespace TestProgressBar
{
    public class MyProgressBar : ProgressBar
    {
        public MyProgressBar() : base()
        {
            Draw += (sender, e) =>
            {
                e.Graphics.DrawString(Value + " / " + MaximumValue, new Font("Arial", (float) 10.0, FontStyle.Regular), Brushes.Black, new PointF(Width / 2 - 10, Height / 2 - 7));//you can also use the Font property as the font
            };
        }
    }
}

Form而不是默认的ProgressBar课程中使用此课程。 然后,您只需将进度条的MaximumValue设置为filesLength,然后继续增加Value属性,直到达到最大值{{1} }。

基本上,在filesLength函数中,您会说:

renameAndResizeFiles()

这将消除对任何其他功能的需求。

P.S。为什么你的功能是基于Camel的? C#函数命名约定规定函数是PascalCased(有人为此提供了一个链接吗?)。所以每个函数名中的第一个字母都要大写。然而,它只是一个惯例。

答案 2 :(得分:1)

我开发了一个名为SxProgress的类,而不是BackgroundWorker,它有一个非常简单的接口,您可以通过以下方式使用它:

string[] fileEntries = Directory.GetFiles(directory) ;
object[] UserObjects = new object[] { fileEntries } ;  
SxProgress.Execute("Processing files",fileEntries.Length,
                   true,  // display labels, i.e. "12/345"
                   false, // no stop button
                   renameAndResizeFiles_ExecInThread,UserObjects) ;

private bool renameAndResizeFiles_ExecInThread(int ItemIndex,object[] UserObjects) 
{
   string[] fileEntries = (string[])UserObjects[0] ;
   string filetoprocess = fileEntries[ItemIndex] ;  
   // handle file work here
   return true ;
}

为了显示进度,该类创建一个包含ProgressBar和Labels的表单,并可选择处理" Stop"按钮来中断过程。

链接到SxProgress概述和源代码: https://stackoverflow.com/questions/30829395/an-easy-to-use-progress-bar-for-winforms

另请注意,该类为并行进程提供了相同的简单接口,可以创建与计算机中的核心一样多的线程,并将项目透明地分发到不同的线程: 只需按SxProgress.Execute()更改SxProgress.ExecuteMulti()