C# Winforms: User Control to blink labels in Legacy project NET 1.1

311 views Asked by At

I am trying to make a User Control to blink a label.

I have found this example:

using System.Diagnostics;
using System.Threading.Tasks;

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;  // ERROR #1
                var per = (double)Math.Abs(n - halfCycle) / halfCycle; 
                var red = (short)Math.Round((c2.R - c1.R) * per) + c1.R; // ERROR #2
                var grn = (short)Math.Round((c2.G - c1.G) * per) + c1.G; // ERROR #3
                var blw = (short)Math.Round((c2.B - c1.B) * per) + c1.B; // ERROR #4
                var clr = Color.FromArgb(red, grn, blw);
                if (BkClr) ctrl.BackColor = clr; else ctrl.ForeColor = clr;
            }
        }

Since I want to implement it in a legacy project NET 1.1 I need to convert above piece of code to make it work so I have implemented below user control:

public class UCSoftBlink : System.Windows.Forms.Label
{
    /// <summary> 
    /// Required designer variable.
    /// </summary>
    private System.ComponentModel.Container components = null;
    private bool exit = false;
    private DateTime startTime = new DateTime();
    private TimeSpan elapsedTime = new TimeSpan();      
    private Timer timer = new Timer();
    private delegate void blinkingDelegate(Label lbl, Color clr1, Color clr2, short CycleTime_ms, bool bkClr);
    public static UCSoftBlink _ucSoftBlink;

    private UCSoftBlink()
    {
        // This call is required by the Windows.Forms Form Designer.
        InitializeComponent();

        timer.Tick += new EventHandler( timer_Tick );
        timer.Interval = (1000) * (1); 
        timer.Enabled = true; 
    }

    public static void StartBlinking(Label lbl, Color clr1, Color clr2, short CycleTime_ms, bool bkClr)
    {
        _ucSoftBlink = new UCSoftBlink();

        blinkingDelegate bd = new blinkingDelegate(_ucSoftBlink.Blink);
        bd.BeginInvoke(lbl, clr1, clr2, CycleTime_ms, bkClr, null, null);
    }

    public static void StopBlinking()
    {
        _ucSoftBlink.timer.Stop();
        _ucSoftBlink.exit = true;
    }

    private void Blink(Label lbl, Color clr1, Color clr2, short CycleTime_ms, bool bkClr)
    {
        _ucSoftBlink.timer.Start();
        _ucSoftBlink.startTime = DateTime.Now;          

        short halfCycle = (short)Math.Round(CycleTime_ms * 0.5);
        while (!exit)
        {
            System.Threading.Thread.Sleep(1000);
            short n = _ucSoftBlink.elapsedTime.TotalMilliseconds % CycleTime_ms; // ERROR #1
            double per = (double)Math.Abs(n - halfCycle) / halfCycle;
            short red = (short)Math.Round((clr2.R - clr1.R) * per) + clr1.R; ERROR #2
            short grn = (short)Math.Round((clr2.G - clr1.G) * per) + clr1.G; ERROR #3
            short blw = (short)Math.Round((clr2.B - clr1.B) * per) + clr1.B; ERROR #4
            Color clr = Color.FromArgb(red, grn, blw);

            if (bkClr) 
            {
                lbl.BackColor = clr; 
            }
            else
            {
                lbl.ForeColor = clr;
            }
        }

        Dispose(true);
    }

    private void timer_Tick(object sender, EventArgs e)
    { 
        _ucSoftBlink.elapsedTime = DateTime.Now - _ucSoftBlink.startTime;
    }

    /// <summary> 
    /// Clean up any resources being used.
    /// </summary>
    protected override void Dispose( bool disposing )
    {
        if( disposing )
        {
            if(components != null)
            {
                _ucSoftBlink.timer.Stop();
                _ucSoftBlink.timer.Tick -= timer_Tick; // // ERROR #5 I know this is possible in other version of NET (>=2.0).
                components.Dispose();
            }
        }
        base.Dispose( disposing );
    }

    #region Component Designer generated code
    /// <summary> 
    /// Required method for Designer support - do not modify 
    /// the contents of this method with the code editor.
    /// </summary>
    private void InitializeComponent()
    {
        components = new System.ComponentModel.Container();
    }
    #endregion
}

but I get some compilation errors:

ERROR #1 error CS0197: Cannot pass 'My.Controls.UCSoftBlink.elapsedTime' as ref or out, because 'My.Controls.UCSoftBlink.elapsedTime' is a marshal-by-reference class
ERROR #1 error CS0029: Cannot implicitly convert type 'double' to 'short'
ERROR #2 error CS0029: Cannot implicitly convert type 'int' to 'short'
ERROR #3 error CS0029: Cannot implicitly convert type 'int' to 'short'
ERROR #4 error CS0029: Cannot implicitly convert type 'int' to 'short'
ERROR #5 error CS0654: Method 'sdpiu.Controles.UCSoftBlink.timer_Tick(object, System.EventArgs)' referenced without parentheses

I want StartBlinking, StopBlinking to be static so I can access without the need of instantiate the user control.

1

There are 1 answers

0
Jonathan Applebaum On

You can create a class with static methods and properties to handle this task on another thread and use a delegate in order to access safely to GUI controls, here is a basic approach, you can improve it for your specific needs.

calling the class from your user control:

public void StartBlink()
{
    BlinkMe.BlinkedLabel = this.label1;
    // start blinking
    System.Threading.Thread t1 = new System.Threading.Thread(BlinkMe.Blink);
    t1.Start();
}
private void btnStopBlinking_Click(object sender, EventArgs e)
{
    // stop blinking
    BlinkMe.IsBlinking = false;
}

the class that will handle the blink:

class BlinkMe
{
    public static Label BlinkedLabel;
    public static int milisec = 500;
    public delegate void BlinkDel();
    public static bool IsBlinking { get; set; } = true;

    public static void Blink()
    {

        while (IsBlinking)
        {
            System.Threading.Thread.Sleep(milisec);
            BlinkedLabel.Invoke(new BlinkDel(DoBLink));
        }
    }

    public static void DoBLink()
    {
        if (BlinkedLabel.BackColor != Color.Yellow)
        {
            BlinkedLabel.BackColor = Color.Yellow;
        }
        else
        {
            BlinkedLabel.BackColor = Color.Green;
        }
    }
}