C# Windows 窗体 Blink 标签

本文关键字:标签 Blink 窗体 Windows | 更新日期: 2023-09-27 18:30:48

在Windows窗体对话框中,我有一个包含近2000行的Listview。每行都有一个复选框。为了方便用户,我在列表视图上方有两个Labels来显示任何活动过滤器以及选择(选中)的行数。

为了强调何时更改过滤器或选择,我想使标签闪烁。因此,我扩展了Label类以支持在文本更改时自动闪烁。但它不起作用!

当我使用Windows.Forms.Timer()标签时,标签可能会闪烁一两次,但并非总是如此,而且通常最终会被隐藏。

当我使用System.Timers.Timer()时,即使我使用InvokeRequired,我也会得到crossthreadException

出了什么问题

:(
class BlinkLabel : Label
{
    private int _blinkFrequency = 621;
    private int _maxNumberOfBlinks = 15;
    private int _blinkCount = 20;
    private bool _isBlinking = false;
    //System.Timers.Timer _timer = new System.Timers.Timer();
    Timer _timer = new Timer();
    public BlinkLabel(){}
    public BlinkLabel(int frequency, int maxNrBlinks)
    {
        _blinkFrequency = frequency;
        _maxNumberOfBlinks = 15;
    }
    protected override void OnTextChanged(System.EventArgs e)
    {
        base.OnTextChanged(e);
        if (!_isBlinking)
        {
            base.ForeColor = System.Drawing.Color.Purple;
            StartBlink();
        }
    }
    public void StartBlink()
    {
        this._isBlinking = true;
        base.Visible = true;
        this._timer.Interval = this._blinkFrequency;
        this._timer.Enabled = true;
        //this._timer.AutoReset = true;
        //this._timer.Elapsed += new System.Timers.ElapsedEventHandler(_timer_Elapsed);
        this._timer.Tick += new EventHandler(_timer_Tick);
        this._timer.Start();
    }
    void _timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        //SYSTEM.TIMERS.TIMER() TICK
        if (this.InvokeRequired)
        {
            this.Invoke(new MethodInvoker(() => { this._timer_Elapsed(sender, e); }));
        }
        else
        {
            base.Visible = !base.Visible;
            this._blinkCount++;
            Application.DoEvents();
            if (this._blinkCount >= this._maxNumberOfBlinks)
            {
                this._timer.Stop();
                this._blinkCount = 0;
                base.Visible = true;
                this._isBlinking = false;
            }
        }
    }
    void _timer_Tick(object sender, EventArgs e)
    {
        //WINDOWS.FORMS.TIMER TICK
        this.Visible = !this.Visible;
        this._blinkCount++;
        Application.DoEvents();
        if (this._blinkCount >= this._maxNumberOfBlinks)
        {
            this._timer.Stop();
            this._blinkCount = 0;
            //base.Visible = true;
            this.Visible = true;
            this._isBlinking = false;
        }
    }
}

C# Windows 窗体 Blink 标签

有几个错误,很难调试。 主要问题是您忘记将_blinkCount重置回 0。 非常有害的是,您一遍又一遍地订阅 Tick 事件处理程序,导致 Tick 事件处理程序针对每个时钟周期运行多次。 使用Application.DoEvents()尤其错误,也使得它几乎无法调试。

重写此代码:

using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
class BlinkLabel : Label {
    private const int _maxNumberOfBlinks = 2 * 3;
    private int _blinkCount = 0;
    private Timer _timer;
    private Color oldColor;
    public BlinkLabel() {
        this._timer = new Timer();
        this._timer.Tick += new EventHandler(_timer_Tick);
        this._timer.Interval = 621;
    }
    protected override void OnTextChanged(System.EventArgs e) {
        base.OnTextChanged(e);
        if (!this._timer.Enabled && base.IsHandleCreated) StartBlink();
    }
    public void StartBlink() {
        this._blinkCount = 0; 
        base.Visible = true;
        this.oldColor = base.ForeColor;
        base.ForeColor = System.Drawing.Color.Purple; 
        this._timer.Start();
    }
    private void _timer_Tick(object sender, EventArgs e) {
        base.Visible = !base.Visible;
        this._blinkCount++;
        if (this._blinkCount >= _maxNumberOfBlinks) {
            this._timer.Stop();
            base.Visible = true;
            base.ForeColor = oldColor;
        }
    }
}

如注释中所述,以下是在窗体上绘制矩形的基础知识(来自本文):

using System;
using System.Drawing;
using System.Windows.Forms;
namespace WindowsFormsApplication5
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        // Get your rectangle size from your text box
        Rectangle tbSize = new Rectangle(10, 10, 50, 20); 
        // invalSize must be slightly bigger due to where the lines are drawn
        Rectangle invalSize = new Rectangle(10, 10, 51, 21); 
        Timer _timer = new Timer();
        bool painting = true;
        private void Form1_Load(object sender, EventArgs e)
        {
            this._timer.Interval = 1000;
            this._timer.Enabled = true;
            this._timer.Tick += new EventHandler(_timer_Tick);
            this._timer.Start();
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            if (painting)
            {
                // e.Graphics uses what Windows has decided needs to be repainted
                // eg only the small rectangle we are drawing, or our rect and
                // a control on the other side of the form
                DrawBorderRect(tbSize, e.Graphics); 
            }
        }
        private void DrawBorderRect(Rectangle coords, Graphics dc)
        {
            Pen bluePen = new Pen(Color.Blue, 1);
            dc.DrawRectangle(bluePen, coords);
        }
        private void _timer_Tick(object sender, EventArgs e)
        {
            painting = !painting;
            // This will make Windows raise a paint event so we don't have to.
            // Doing it this way allows Windows to combine multiple small paint
            // events to maximise efficiency
            this.Invalidate(invalSize); 
        }
    }
}

只需将其放入新形式中,然后观察闪烁的蓝色框:)