0

I have a Label in a statusbar in my view with which I show messages to the user. I want to show the message and change background color only for a few seconds, so that I wouldn't have to clear the label with extra lines of code.

I have a StatusText and StatusColor properties in the viewmodel, and the label content and color are bound to these, and are working fine.

My question is how do I time it in ViewModel?

Can I use a timer in the viewmodel method and in a way that doesn't freeze the UI while displaying the message?

I'm trying to adher to the MVVM framework, but I couldn't find any solutions on SO without using events. Is it possible in some simple fashion?

Louis Go
  • 2,213
  • 2
  • 16
  • 29
mpn275
  • 113
  • 1
  • 12

2 Answers2

1

Using Command instead of event. Command will find a ICommand property with matched name in ViewModel. That will decouple your View and Code-behind.

In xaml

<Button Command="ChangeColorCommand" />

In ViewModel Note: timer is System.Timers.Timer. I skipped its instantiated code.

TimerTicked is called when timer Elapsed.

You don't have to use DispatcherTimer because StatusText and StatusColor are not UI object.

    public ICommand ChangeColorCommand
    {
        get
        {
            return new RelayCommand( ChangeColorAndMessage );
        }
    }
    // This is your view model constructor
    private void ViewModelCtor(){
       // your initialize code here

        //subscribe event once
        timer = new Timer();
        timer.Interval=1000;
        timer.AutoReset=false;
        timer.Elapsed += TimerTicked;
    }

    public void ChangeColorAndMessage( string[] args )
    {
        StatusText = "Button pressed";
        StatusColor = changedColor;

        // You implementation for changing it back.
        timer.Enabled = true;
    }

    private void TimerTicked( object sender, EventArgs e )
    {
        StatusText = "origin";
        StatusColor = originColor;

        // Fire property changed to notify view updating data.
        PropertyChanged( this, new PropertyChangedEventArgs( StatusText ) );
        PropertyChanged( this, new PropertyChangedEventArgs( StatusColor ) );
    }

For implementation of RelayCommand, refer to this post

Louis Go
  • 2,213
  • 2
  • 16
  • 29
  • Thanks for the answer. I do have RelayCommand implemented, and all my buttons are bound to relaycommands. The StatusText is changed in the method tied to a relaycommand, just as in your example. But the question is, how do I time it there? Can I use a timer in the viewmodel method and in a way that doesn't freeze the UI while displaying the message? – mpn275 Feb 25 '20 at 20:52
  • See my edit. You don't have to use `DispatcherTimer` since you don't modify UI directly. Also using timer will not freeze UI. – Louis Go Feb 26 '20 at 02:00
  • I had to add the bit `timer.Elapsed += TimerTicked;` in order for it to work. Added the code in a new answer. – mpn275 Feb 27 '20 at 19:18
1

Just posting my solution here, thanks for Louis Go for help.

So, I added the the timer in the VM constructor and the following methods in the viewmodel for changing the StatusTextand StatusColor properties and to change them back. The properties themselves handle the change notification.

private System.Timers.Timer timer;
private VMConstructor()
{
    timer = new System.Timers.Timer(3000);
    timer.AutoReset = false;
    timer.Elapsed += TimerTicked;
}

private void ChangeStatus(string text, string color)
{
    timer.Enabled = true;
    StatusText = text;
    StatusColor = color;
}

private void TimerTicked(object sender, EventArgs e)
{
    StatusColor = "Grey";
    StatusText = "";
}
mpn275
  • 113
  • 1
  • 12