C# 动画片;“发光”;在所有者绘制的进度条中(ListView/DataGridView)

C# 动画片;“发光”;在所有者绘制的进度条中(ListView/DataGridView),c#,listview,animation,windows-vista,progress-bar,C#,Listview,Animation,Windows Vista,Progress Bar,我注意到.NET2.0(Winforms)中的bog标准ProgressBar在Vista中显示为一个奇特的动画发光条;但是,使用ProgressBinderer(通常在所有者绘制的列表视图、栅格视图或其他类似控件中绘制进度条时必须这样做)只会提供视觉样式,而不会产生漂亮的动画 我想这是愚蠢的期待,这将只是神奇的工作-我想象在Vista中的本机控件必须有某种嵌入式计时器或线程,显然不存在时,绘制静态图像。我确实看到,如果您连续多次重画ProgressBar控件(使用DrawToBitmap),您

我注意到.NET2.0(Winforms)中的bog标准ProgressBar在Vista中显示为一个奇特的动画发光条;但是,使用ProgressBinderer(通常在所有者绘制的列表视图、栅格视图或其他类似控件中绘制进度条时必须这样做)只会提供视觉样式,而不会产生漂亮的动画

我想这是愚蠢的期待,这将只是神奇的工作-我想象在Vista中的本机控件必须有某种嵌入式计时器或线程,显然不存在时,绘制静态图像。我确实看到,如果您连续多次重画ProgressBar控件(使用DrawToBitmap),您实际上可以看到动画光晕的不同阶段,因此我尝试使用计时器自动重画,但外观不太正确,而且它也比实际的ProgressBar占用更多的CPU时间

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


我想知道是否有人有过将进度条嵌入用户绘制控件的经验,并且可能知道一种比上述两种方法更好的方法——这种方法可以准确地再现发光/闪烁,而不需要依赖计时器和/或敲击CPU。

我不得不使用一些非常疯狂的特技来实现这一点。不幸的是,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);
    }
  }

}

尝试将其集成到列表控件中会很有趣-我不确定是否会浪费更多的CPU周期使每个项目无效,或者测量所有字体和其他元素以尝试找出要无效的进度条的确切界限。看起来它会工作的,谢谢。这对我来说非常有用,但是没有必要使用反射来创建新的VisualStyle元素。您可以使用静态VisualStyleElement.CreateElement函数来解决此问题。请注意,其他发现此问题的人。。。控制面板的“易于访问”区域有一个选项“禁用所有不必要的动画”。如果启用了该选项,则无论您尝试什么,都无法使动画正常工作。浪费了很多时间去学习。