Search code examples
c#wpftimerstatusbar

Blinking text in status bar


I am trying to implement a warning system when a user tries to do an illegal action in my form. The idea is to call StatusBarFade method, give it the parameter it should write, than have that method display the text, make it blink by changing it's color for a second and a half, and then stay another second and a half, after which the text will disappear.

The blinking works every other time, while the text disappears normally.

Please note that I know this code is quite messy and there is surely a better way to do it, but since I don't exactly know how delegates work I don't know how to utilize them properly. Hopefully someone will be able to explain what I'm doing wrong. Anyway, after some testing I realized that it's best to have two timers. The problem is that this code works every other time.

    private Timer timer = new System.Timers.Timer();
    private Timer timerColor = new System.Timers.Timer();
    private void StatusBarFade(string ispis)
    {
        statusBar1AS2.Content = ispis;
        int i = 0;
        timerColor.Interval = 100;
        timerColor.AutoReset = true;
        timerColor.Elapsed += delegate(object sender, System.Timers.ElapsedEventArgs e)
        {
            this.Dispatcher.BeginInvoke(new Action(() =>
                {
                    ++i;
                    if (statusBar1AS2.Foreground == Brushes.Black)
                        statusBar1AS2.Foreground = Brushes.Gold;
                    else
                        statusBar1AS2.Foreground = Brushes.Black;
                    if (i > 15)
                    {
                        statusBar1AS2.Foreground = Brushes.Black;
                        i = 0;
                        timerColor.Stop();
                    }
                }));
        };
        timerColor.Start();

        timer.Interval = 3000;
        timer.Elapsed += delegate(object sender, System.Timers.ElapsedEventArgs e)
        {
            timer.Stop();
            this.Dispatcher.BeginInvoke(new Action(() => { statusBar1AS2.Content = ""; }));
        };
        timer.Start();
    }

As far as I understand delegates, I shouldn't be adding the same delegate to the timer.Elapsed event every time the text is changed, but rather only once, in the constructor, for example. The problem is that I don't know how to use the counter i in the way that I did in the code.


Solution

  • You could simply use the following animation:

    var animation = new ColorAnimation
    {
        From = Colors.Black,
        To = Colors.Gold,
        AutoReverse = true,
        Duration = TimeSpan.FromSeconds(0.1),
        RepeatBehavior = new RepeatBehavior(TimeSpan.FromSeconds(1.5))
    };
    
    animation.Completed += (o, e) => statusBar.Content = string.Empty;
    
    statusBar.Foreground = new SolidColorBrush();
    statusBar.Foreground.BeginAnimation(SolidColorBrush.ColorProperty, animation);
    

    UPDATE: In order to delay the removal of the message, you may of course use a timer. You could perhaps write your StatusBarFade method like shown below, with a DispatcherTimer:

    private void StatusBarFade(string message)
    {
        statusBar.Content = message;
    
        var animation = new ColorAnimation
        {
            From = Colors.Gold,
            To = Colors.Black,
            AutoReverse = true,
            Duration = TimeSpan.FromSeconds(0.1),
            RepeatBehavior = new RepeatBehavior(TimeSpan.FromSeconds(1.5)),
        };
    
        statusBar.Foreground = new SolidColorBrush();
        statusBar.Foreground.BeginAnimation(SolidColorBrush.ColorProperty, animation);
    
        var timer = new DispatcherTimer
        {
            Interval = TimeSpan.FromSeconds(4.5)
        };
    
        timer.Tick +=
            (o, e) =>
            {
                timer.Stop();
                statusBar.Content = string.Empty;
            };
    
        timer.Start();
    }