Centralising RaiseCanExecuteChanged Logic in an MVVM Light Portable View Model

When working with an MVVM Light sometime we need to “tell” the view that a command’s ability to be executed has changed.

For example, when a user clicks a Start button to start a countdown, the Start button should be disabled and the pause button should then be enabled.

If we’re binding a button to an MVVM Light RelayCommand, the button will automatically disable when then RelayCommand’s CanExecute function returns false.

For this to work, when the user clicks Start, the command will execute, but then we need to tell the Start and Pause commands to raise their CanExecuteChanged events. To do this we can call the RaiseCanExecuteChanged method on each RelayCommand that logically makes sense for our application.

One approach is to put this in each property setter, for example:

public const string IsPlayingPropertyName = "IsPlaying";
protected  bool _isplaying;

public  bool IsPlaying
{
    get
    {
        return _isplaying;
    }

    set
    {
        if (_isplaying == value)
        {
            return;
        }

        RaisePropertyChanging(IsPlayingPropertyName);
        _isplaying = value;
        RaisePropertyChanged(IsPlayingPropertyName);
              
        // RAISE CANEXECUTECHANGED HERE IN PROP SETTER
        PauseCommand.RaiseCanExecuteChanged();
        StartCommand.RaiseCanExecuteChanged();
    }
}

Now when this IsPlaying property changes, the Pause and Start buttons commands can execute will be updated.

A problem with this approach is that the logic to decide which RelayCommands CanExecuteChanged event gets raised in response to which properties are changing is distributed through all the property setters in the ViewModel. This can make it hard to reason about the changes in state of the ViewModel.

One alternative approach is to centralise this logic in a single method.

More...

SHARE:

Portable Class Library (PCL) Timer when Targeting Both Windows 8 and Windows Phone using Reactive Extensions

Currently the Timer class is not available when targeting both Windows Phone 8 and Windows 8 Store Apps.

For the app I’m building I want the MVVMLight PCL ViewModel to update a property every second – the databound View then simply updates itself.

One solution is to implement your own Task based Timer as described in this Stack Overflow article.

Another approach could be to make use of Reactive Extensions Observable.Interval method to create a sequence that updates every n-seconds.

First off add the Reactive Extensions NuGet package to your PCL project.

Next, in the ViewModel constructor (or command, etc.) create the interval stream and then tell it to execute a method every second:

var timer = Observable.Interval(TimeSpan.FromSeconds(1)).DistinctUntilChanged();

timer.ObserveOn(SynchronizationContext.Current).Subscribe(TimerTick);

 

I’m using SynchronizationContext.Current because the TimerTick method (below) updates the ViewModel property, without this there is a thread access problem.

So the TimerTick method ends up being called every second and simply updates the (MVVMLight) TotalTimeLeft property:

private void TimerTick(long l)
{
    TotalTimeLeft = DateTime.Now.Second.ToString();
}

I’m not an expert on Rx so there may be a better way of using it in this instance (or some potential hidden problems) but it’s working in the app so far (and on ARM Surface RT)…

It’s however cool to know that Rx has portable class library support.

Any Rx experts feel free to comment on a better way :)

SHARE: