1

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

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

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

当我使用时System.Timers.Timer()crossthreadException即使我使用InvokeRequired.

怎么了 :(

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;
        }
    }
}
4

2 回答 2

1

正如评论中所讨论的,这里是在表单上绘制矩形的基础知识(来自这篇文章):

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); 
        }

    }
}

只需将其放入新形式并观看闪烁的蓝色框:)

于 2013-09-09T09:36:35.973 回答
1

有几个错误,很难调试。主要问题是您忘记将 _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;
        }
    }
}
于 2013-09-09T10:42:30.827 回答