piątek, 4 marca 2016

MVVM - Improving RelayCommand

One of the simpliest and ingenious things separating views from view models is ICommand. Three simple methods this interface provide enough functionality to satisfy most of user input scenarios, on top of that we receive full control during unit testing. RelayCommand is simple implementation of that interface. Usually taking Action to execute and Predicate for CanExecute check. Those two probably won't change because there's nothing specific about them. What already changed is the way that CanExecuteChanged is raised.

With WPF applications we have CommandManager.RequerySuggested event inside System.Windows.Input namespace. That one is being raised when user interacts with UI.

If you set the breakpoint within your condition and debug it, you'll see that it's being hit almost instantly after you get focus on UI. Brutal but easy to use.

Now when I was trying to do the same in Windows Phone 8.1 app, surprise came at once. CommandManager doesn't exist anymore. Vanished. Oh no, what now. I did some quick search on the net and the most obvious solution appeared. Right now you can simply expose invocator from your command and call it from your ViewModel. Wow!

Yea, what a mess. Alright, I don't want it. So I hooked up on what I already have. My ViewModel already have INotifyPropertyChanged implemented on it. Why not. I derieved from RelayCommand and created WatchingRelayCommand. As the name says - it's watching. Watching the properties that can affect its execution. All I need to do is to pass context and the property names. It's attaching itself to INotifyPropertyChanged on context and each time when some property changes on the ViewModel, command checks if it's interested in that property and if so raises CanExecuteChanged.

On top of that small test ViewModel and couple of tests. When the RelayCommandTestViewModel is instantiated condition is not satisfied (Id as integer by default sets to 0). Constructor creates command with condition that will check if value passed in constructor is matched with changed Id. You can see that if condition is still not satisfied event won't trigger. Thats actually because my implementation of RelayCommand that checks previous state of condition.

Brak komentarzy:

Prześlij komentarz