6

我注意到 .NET 2.0 (Winforms) 中的标准 ProgressBar 确实在 Vista 中显示为精美的动画发光条。然而,使用 ProgressBarRenderer(当试图在所有者绘制的列表视图、网格视图或其他此类控件中绘制进度条时通常必须这样做)只会给出没有漂亮动画的视觉样式。

我想期望这会神奇地工作是愚蠢的——我想Vista中的本机控件必须有某种嵌入式计时器或线程,在绘制静态图像时显然不存在。我确实看到,如果您连续多次重绘 ProgressBar 控件(使用 DrawToBitmap),您实际上可以看到动画发光的不同阶段,所以我尝试使用计时器来保持自动重绘,但有些地方不太对劲外观,它也比实际的 ProgressBar 消耗更多的 CPU 时间。

这似乎给我留下了两个不合标准的选择:a)使用 ProgressBarRenderer 并最终得到 Vista“外观”但没有动画;或 b) 使用计时器不断地将多个 ProgressBars 重绘为位图,并浪费 CPU 周期以使其看起来更好但仍不完美。

我想知道是否有人有在自绘控件中嵌入进度条的经验,并且可能知道比上述两个选项更好的方法 - 无需依赖计时器和/或敲击 CPU 即可准确再现发光/闪烁的方法。

4

1 回答 1

6

我不得不做一些非常疯狂的特技来完成这项工作。不幸的是,MSFT 没有更新 VisualStyleElement.ProgressBar 类来添加 Vista 添加的部分。并且构造函数是私有的。我不得不猜测产生动画的部分。我与这段代码相当接近,它应该给你一些实验的东西:

using System;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
using System.Reflection;

namespace WindowsFormsApplication1 {
  public partial class Form1 : Form {
    VisualStyleElement pulseOverlay;
    VisualStyleElement moveOverlay;
    VisualStyleRenderer pulseRenderer;
    VisualStyleRenderer moveRenderer;
    Timer animator = new Timer();
    public Form1() {
      InitializeComponent();
      ConstructorInfo ci = typeof(VisualStyleElement).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance,
        null, new Type[] { typeof(string), typeof(int), typeof(int) }, null);
      pulseOverlay = (VisualStyleElement)ci.Invoke(new object[] { "PROGRESS", 7, 0 });
      moveOverlay = (VisualStyleElement)ci.Invoke(new object[] { "PROGRESS", 8, 0 });
      pulseRenderer = new VisualStyleRenderer(pulseOverlay);
      moveRenderer = new VisualStyleRenderer(moveOverlay);
      animator.Interval = 20;
      animator.Tick += new EventHandler(animator_Tick);
      animator.Enabled = true;
      this.DoubleBuffered = true;
    }
    void animator_Tick(object sender, EventArgs e) {
      Invalidate();
    }

    int xpos;
    protected override void OnPaint(PaintEventArgs e) {
      Rectangle rc = new Rectangle(10, 10, 100, 20);
      ProgressBarRenderer.DrawHorizontalBar(e.Graphics, rc);
      rc = new Rectangle(10, 10, 50, 20);
      ProgressBarRenderer.DrawHorizontalChunks(e.Graphics, rc);
      xpos += 3;
      if (xpos >= 30) xpos = -150;  // Note: intentionally too far left
      rc = new Rectangle(xpos, 10, 50, 20);
      pulseRenderer.DrawBackground(e.Graphics, rc);
      moveRenderer.DrawBackground(e.Graphics, rc);
    }
  }

}
于 2008-11-17T21:45:30.403 回答