【问题标题】:Extending ProgressBar causes delay on first value change扩展 ProgressBar 会导致第一次值更改的延迟
【发布时间】:2013-12-05 04:49:49
【问题描述】:

我创建了一个扩展 ProgressBar 的类 - 主要是为了允许更多的自定义,所以我可以在栏上绘制刻度,选择我想要的颜色,并摆脱默认的动画等等。它在大多数情况下都可以正常工作,但是第一次更改值时,在实际更新之前总是会有大约一秒钟的延迟。所有后续的更改都会立即发生,只是第一次从 0 变为 1 会延迟。我正在尝试确定是否存在某种我必须以某种方式规避的内置延迟?这是我的代码的相关位:

public class FancyProgressBar : ProgressBar
{
    //... various properties and fields

    public FancyProgressBar()
    {
        this.SetStyle(ControlStyles.UserPaint, true);
        this.DoubleBuffered = true;

        InitializeComponent();
    }
    public FancyProgressBar(IContainer container)
    {
        this.SetStyle(ControlStyles.UserPaint, true);
        this.DoubleBuffered = true;

        container.Add(this);

        InitializeComponent();
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        Rectangle rec = e.ClipRectangle;

        rec.Width = (int)(rec.Width * ((double)Value / Maximum)) - 4;

        if (ProgressBarRenderer.IsSupported)
            ProgressBarRenderer.DrawHorizontalBar(e.Graphics, e.ClipRectangle);
        else
            e.Graphics.DrawRectangle(Pens.Gray, 0, 0, this.Width, this.Height);

        rec.Height = rec.Height - 4;

        DrawBar(e.Graphics, new Color[] { Color1, Color2, Color3 }, e.ClipRectangle, rec);

        if (Ticks > 0)
        {
            int lineHeight = this.Height * TickHeight / 100;
            float spacing = this.Width / Ticks;
            for (int i = 1; i < Ticks; i++)
            {
                Pen pen = new Pen(new SolidBrush(TickColor));
                e.Graphics.DrawLine(pen, new Point((int)(spacing * i)-2, Height), new Point((int)(spacing * i)-2, Height - lineHeight));
            }
        }
    }

    //This is broken out into a separate function because I have another version
    //that draws more than one bar.  Shouldn't make a difference though.
    private void DrawBar(Graphics g, Color[] colors, Rectangle clipRec, Rectangle drawRec)
    {
        using (System.Drawing.Drawing2D.LinearGradientBrush l =
            new System.Drawing.Drawing2D.LinearGradientBrush(clipRec, Color.Green, Color.Red, 0f))
        {
            System.Drawing.Drawing2D.ColorBlend lb = new System.Drawing.Drawing2D.ColorBlend();
            lb.Colors = colors;
            lb.Positions = new float[] { 0, PositionColor2, 1.0f };
            l.InterpolationColors = lb;

            g.FillRectangle(l, 2, 2, drawRec.Width, drawRec.Height);
        }

        using (System.Drawing.Drawing2D.LinearGradientBrush l2 =
            new System.Drawing.Drawing2D.LinearGradientBrush(clipRec,
                Color.FromArgb(147, 255, 255, 255),
                Color.FromArgb(0, 255, 255, 255),
                System.Drawing.Drawing2D.LinearGradientMode.Vertical))
        {
            System.Drawing.Drawing2D.ColorBlend lb = new System.Drawing.Drawing2D.ColorBlend();
            lb.Colors = new Color[] { Color.FromArgb(40, 255, 255, 255), Color.FromArgb(147, 255, 255, 255),
                Color.FromArgb(40, 255, 255, 255), Color.FromArgb(0, 255, 255, 255) };
            lb.Positions = new float[] { 0, 0.12f, 0.39f, 1.0f };
            l2.InterpolationColors = lb;

            l2.WrapMode = System.Drawing.Drawing2D.WrapMode.Tile;
            g.FillRectangle(l2, 2, 2, drawRec.Width, drawRec.Height);
        }
    }

编辑: 我应该声明我没有使用 ProgressBar 作为实际的进度条。它在加载内容时不会运行,只是在 UI 中显示一些值,因此不一定同时进行其他一些昂贵的计算。

【问题讨论】:

    标签: c# winforms progress-bar


    【解决方案1】:

    尝试使用 BackgroundWorker 的 ProgressBar,因为 UI 元素具有不同的 Thread。像这样:

        BackgroundWorker bwEx = new BackgroundWorker();
        bwEx.DoWork += bwEx_DoWork;
        bwEx.RunWorkerCompleted += bwEx_RunWorkerCompleted;
        bwEx.ProgressChanged += bwEx_ProgressChanged;
        bwEx.WorkerReportsProgress = true;
        bwEx.RunWorkerAsync();
    
        private void bwEx_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
           yourProgress.Value = e.ProgressPercentage;
        }
    
        private void bwEx_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
    
        }
    
        private void bwEx_DoWork(object sender, DoWorkEventArgs e)
        {
    
        }
    

    【讨论】:

    • 恐怕我还是错过了什么。我不知道这应该如何改变任何事情。代替myProgressBar.Value = x; 我已经把bwEx.ReportProgress(X); 它现在可以工作了,但是当你第一次这样做时仍然有1 秒的延迟,所以没有什么是固定的。此外,这真的很不方便,因为我在屏幕上有大约十几个 FancyProgressBars,并且为每个人设置一个 BackgroundWorker 似乎代码太多而没有真正的好处。 (似乎没有一种简单的方法可以将一个 BackgroundWorker 用于多个 ProgressBar。)
    【解决方案2】:

    好的,我终于在这里想出了一个真正的解决方案。 ProgressBar 的东西是完全没有必要的。我只是将我的FancyProgressBar 更改为扩展Control 而不是ProgressBar,然后添加了ValueMinimumMaximumStep 的字段,它们实际上是ProgressBar 的唯一部分我还在使用,因为我已经覆盖了绘图部分。我必须添加的唯一另一件事是每当值更改时在进度条上调用Invalidate()。这在从ProgressBar 扩展时不起作用,这似乎有某种内置延迟,可能是因为它被设计为多线程对象。由于我实际上并没有将它用作加载栏,因此完全不需要多线程。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-20
      • 1970-01-01
      • 1970-01-01
      • 2013-06-11
      • 2020-08-25
      • 1970-01-01
      相关资源
      最近更新 更多