Possible to scope Command CanExecute calls?

Jun 30, 2011 at 9:19 AM

Not sure if this question is directly related to Cinch or just WPF, but I noticed that the CanExecute handlers for Commands (SimpleCommands) get called for all currently opened ViewModel's e.g. if I've got a parent ViewModel that has commands which then opens a child ViewModel, the CanExecute handlers in the parent ViewModel keep getting fired even though it doesn't make sense as the parent ViewModel doesn't have the focus. It seems like a potential performance hit if you've got dozens of ViewModels opening each other, each containing lots of Commands. I know the code in the CanExecute handlers should be short n fast, but still seems kinda stupid to have them firing off all over the place each time I move the mouse or change control focus etc on a totally unrelated window.

Is it somehow possible to place a scope on a ViewModels Commands so their CanExecute handlers are only fired when they are in scope i.e. when the ViewModel has the focus?

 

Cheers,

Shane

Jun 30, 2011 at 10:17 AM

You could bind the ViewModel to IsFocused property (would need to add a extra dp property to the view to be bindable) and check it on CanExecute. Another way would be to use your own SimpleCommand implementation and fire the CanExecuteChanged event on your own requirements.

But out of the box that isn't possible.

Maybe the answere here could help you:

http://stackoverflow.com/questions/1751966/commandmanager-invalidaterequerysuggested-isnt-fast-enough-what-can-i-do

Coordinator
Jun 30, 2011 at 2:10 PM

What Helmut said is a good approach, and its actually pretty close to what PRISM uses where it has this concept of IActiveAware in commands.

 

Thing with Cinch that I do like, is if you do not like my code, its not too hard for you to swap most parts out. I hope you agree.

 

You seem to be getting on well enough with it though, no?

Jul 1, 2011 at 4:36 AM

Yeah Cinch is awesome sacha and like you suggested i've been modifying & overriding bits n pieces to suit my needs. I've only just started my transition into the MVVM & WPF worlds so I'm still coming to grips with their quirks, but Cinch has helped immensely.

I'll play around with these options and see how i go, but they look like they should do the trick.

 

Thanks for your help guys

Coordinator
Jul 1, 2011 at 9:10 AM

No worries. Helmut has actually added quite a lot of useful feedback on this project, and has helped a lot of people out on the forums, great, as I did not even know he did it. Glad you like Cinch.

 

PS : I will be doing a few updates over next week or so, things that people have commented on, that are not massive, just small enhancements, but I will be introducing a new threading control which aids the development of threading and keeping user informed of what is going on. So watch out for those

Coordinator
Jul 1, 2011 at 9:11 AM

Helmut,

 

Just wanted to say thanks for all your input on answering some Cinch issues here man, its really appreciated

Jul 4, 2011 at 6:15 AM
Edited Jul 4, 2011 at 7:05 AM

fyi, I ended up using the DelegateCommand code in the link Helmut provided as this has the "IsAutomaticRequeryDisabled" property. In my ViewModelBase class, I created a "CreateCommand" method that inheriting ViewModel's can call to create their commands, which simply creates new DelegateCommands and adds them to a List. I added a "ShowDialog" method to my ViewModelBase class which disables & enables Automatic Requerying for the Commands. Here's the code from my ViewModelBase class:

 

Protected Function CreateCommand(Of T1, T2)(canExecuteMethod As Func(Of T1, Boolean), executeMethod As Action(Of T2)) As DelegateCommand
    Dim command As New DelegateCommand(Of T1, T2)(canExecuteMethod, executeMethod)
    _commands.Add(command)
    Return command
End Function

Public Function ShowDialog(key As String, state As Object) As Nullable(Of Boolean)
    Try 
        'Disable Auto Requerying for all Commands 
        For Each command In _commands             
            command.IsAutomaticRequeryDisabled = True 
        Next 

        'Show the dialog 
        Return _uiVisualizerService.ShowDialog(key, state)    
    Finally 
        'Enable Auto Requerying for all Commands 
        For Each command In _commands
            command.IsAutomaticRequeryDisabled = False 
        Next 
    End Try 
End Function

 

 

I'm sure there's better ways of doing it, but this does the job for me.

Coordinator
Jul 4, 2011 at 4:39 PM

Fair enough. Like I say good thing about Cinch is you can mix and match components quite easily. I have done new code upload this morning for the fix Helmut and you have outlined here, as well as a few other things