6

.NET 2.0 (Winforms) のボグ標準の ProgressBar が、Vista ではファンシーなアニメーションの光るバーとして表示されることに気付きました。ただし、ProgressBarRenderer を使用すると (通常、オーナー描画リスト ビュー、グリッド ビュー、またはその他のコントロールでプログレス バーを描画しようとするときに必要になるため)、きれいなアニメーションのないビジュアル スタイルが得られます。

これが魔法のように機能することを期待するのはばかげていたと思います.Vistaのネイティブコントロールには、静止画像を描画するときには明らかに存在しないタイマーまたはスレッドが埋め込まれている必要があると思います. ProgressBar コントロールを (DrawToBitmap を使用して) 連続して数回再描画すると、アニメーション化されたグローの異なる段階を実際に確認できることがわかったので、タイマーを使用して自動的に再描画を続けることを実験しましたが、何かが正しくありませんまた、実際の ProgressBar よりもはるかに多くの CPU 時間を消費します。

これにより、次の 2 つの標準以下のオプションが残っているようです。または b) タイマーを使用して複数の ProgressBars をビットマップに継続的に再描画し、CPU サイクルを浪費して見栄えを良くしますが、それでも完全ではありません。

所有者が描画したコントロール内にプログレス バーを埋め込んだ経験があり、上記の 2 つのオプションよりも良い方法を知っている人がいるかどうか疑問に思っていました。

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 に答える