убить или обнаружить диманический секундомер? - PullRequest
0 голосов
/ 11 сентября 2018

У меня есть динамическая форма с различными метками, генерируемыми во время выполнения, когда обнаруживается что-то критическое, я устанавливаю метку на мигание через это:

SoftBlink(label, Color.FromArgb(30, 30, 30), Color.Red, 2000, true);

private async void SoftBlink(Control ctrl, Color c1, Color c2, short CycleTime_ms, bool BkClr)
{
    var sw = new Stopwatch(); sw.Start();
    short halfCycle = (short)Math.Round(CycleTime_ms * 0.5);

    while (true)
    {
        await Task.Delay(1);

        var n = sw.ElapsedMilliseconds % CycleTime_ms;
        var per = (double)Math.Abs(n - halfCycle) / halfCycle;
        var red = (short)Math.Round((c2.R - c1.R) * per) + c1.R;
        var grn = (short)Math.Round((c2.G - c1.G) * per) + c1.G;
        var blw = (short)Math.Round((c2.B - c1.B) * per) + c1.B;
        var clr = Color.FromArgb(red, grn, blw);

        if (BkClr) 
            ctrl.BackColor = clr; 
        else 
            ctrl.ForeColor = clr;
    }
}

это отлично работает при первом проходе цикла, но каждыйследующий цикл продолжает добавлять еще один секундомер к метке, и мигание сходит с ума.

Какой лучший способ убить / проверить, если мигание уже установлено на этой метке и не возобновить другой секундомер?

Думаю, мне нужно было бы передать метку, которую я мигаю, SoftBlink и как-то уничтожить существующий секундомер в цикле while true?

Спасибо

Ответы [ 2 ]

0 голосов
/ 11 сентября 2018

Я бы выбрал таймер и класс, который будет обновлять элементы управления. Я считаю плохой практикой использовать ожидание в цикле while. Как ты их остановишь? Это будет более запутанным. Лучше добавлять элементы управления в список и обновлять их по таймеру. Кроме того, не устанавливайте таймер слишком быстро.

Вот пример, я создал новое приложение Windows Forms и добавил две метки и две кнопки на форму. Я создал класс ItemBlinker, который будет отслеживать все добавленные элементы управления и обновлять их:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Windows.Forms;

namespace TestBlink
{
    public partial class Form1 : Form
    {
        private Timer _timer;
        private ItemBlinker _itemBlinker = new ItemBlinker();

        public Form1()
        {
            InitializeComponent();

            // create the timer
            _timer = new Timer();
            _timer.Tick += Timer_Tick;
            _timer.Interval = 10;
            _timer.Enabled = true;
        }

        private void Timer_Tick(object sender, EventArgs e)
        {
            // update all blinkers
            _itemBlinker.Update();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            // add two labels
            _itemBlinker.Add(label1, Color.FromArgb(30, 30, 30), Color.Red, 2000, true);
            _itemBlinker.Add(label2, Color.FromArgb(30, 30, 30), Color.Blue, 3000, true);
        }

        private void button2_Click(object sender, EventArgs e)
        {
            // remove all blinked controls
            _itemBlinker.Clear();
        }
    }


    public class ItemBlinker
    {
        private Dictionary<Control, BlinkItem> _items = new Dictionary<Control, BlinkItem>();
        private Stopwatch _sw = Stopwatch.StartNew();

        public void Add(Control ctrl, Color c1, Color c2, short cycleTime_ms, bool bkClr)
        {
            BlinkItem item;

            // if it allready exists, just restore the colors first.
            if (_items.TryGetValue(ctrl, out item))
                item.RestoreColor();

            _items[ctrl] = new BlinkItem(ctrl)
            {
                C1 = c1,
                C2 = c2,
                CycleTime_ms = cycleTime_ms,
                BkClr = bkClr
            };
        }

        public void Remove(Control ctrl)
        {
            BlinkItem item;

            if (_items.TryGetValue(ctrl, out item))
            {
                item.RestoreColor();
                _items.Remove(ctrl);
            }
        }

        public void Clear()
        {
            foreach (var item in _items.Values)
                item.RestoreColor();

            _items.Clear();
        }

        public void Update()
        {
            // get the elapsedMilliseconds
            var elapsedMilliseconds = _sw.ElapsedMilliseconds;

            foreach (var item in _items.Values)
                item.Update(elapsedMilliseconds);
        }
    }

    public class BlinkItem
    {
        private readonly Color _initFore;
        private readonly Color _initBack;

        public Control Ctrl { get; }
        public Color C1 { get; set; }
        public Color C2 { get; set; }
        public short CycleTime_ms { get; set; }
        public bool BkClr { get; set; }

        public BlinkItem(Control ctrl)
        {
            Ctrl = ctrl;
            _initFore = ctrl.ForeColor;
            _initBack = ctrl.BackColor;
        }

        public void Update(long elapsedMilliseconds)
        {
            var halfCycle = CycleTime_ms / 2;
            var n = elapsedMilliseconds % CycleTime_ms;
            var per = (double)Math.Abs(n - halfCycle) / halfCycle;
            var red = (short)Math.Round((C2.R - C1.R) * per) + C1.R;
            var grn = (short)Math.Round((C2.G - C1.G) * per) + C1.G;
            var blw = (short)Math.Round((C2.B - C1.B) * per) + C1.B;
            var clr = Color.FromArgb(red, grn, blw);
            if (BkClr) Ctrl.BackColor = clr; else Ctrl.ForeColor = clr;
        }

        internal void RestoreColor()
        {
            Ctrl.ForeColor = _initFore;
            Ctrl.BackColor = _initBack;
        }
    }
}

Таким образом, ваша функциональность намного лучше отделена и меньше кода для спагетти. С этой структурой легко убить блинкера. Существует даже метод RestoreColor для восстановления начальных цветов. (добавлено позже) Также я использовал словарь, чтобы не мигать одним и тем же элементом управления дважды.

0 голосов
/ 11 сентября 2018

В свойстве тега Label установите флаг, чтобы указать, мигает он или нет.

bool? blinking = ctrl.Tag as bool?;

Stopwatch sw;
if (!blinking ?? false)
{
    ctrl.Tag = true;
    sw = new Stopwatch();
    while(true)
    {
        // do stuff
    }
    ctrl.Tag = false; // doesn't look like you would ever reach this point.
}
...