New Posts New Posts RSS Feed: DelegateCommand CanExecute and Async
  FAQ FAQ  Forum Search   Calendar   Register Register  Login Login

DelegateCommand CanExecute and Async

 Post Reply Post Reply
Author
LowOrbit View Drop Down
Newbie
Newbie


Joined: 17-Aug-2007
Location: United States
Posts: 20
Post Options Post Options   Quote LowOrbit Quote  Post ReplyReply Direct Link To This Post Topic: DelegateCommand CanExecute and Async
    Posted: 14-Jun-2013 at 9:06am
Hello
 
I have a DeletegateCommand object for a button I my UI. In the CanExecute method of the delegate, I need to execute a query against the database to see if a user is allowed to press the button based on the context of the data they are on. The normal signature of the CanExecute is a Func<bool>.
 
I cannot figure out how to call an async method that returns a bool. In order to return a bool, the signature needs to be a Task<bool> but then it doesn't match the DelegateCommand signature for CanExecute.
 
Can you provide some guidance or an example on how to specifiy a method for CanExecute than can execute a async method that returns a bool?
 
Thanks!
Back to Top
LowOrbit View Drop Down
Newbie
Newbie


Joined: 17-Aug-2007
Location: United States
Posts: 20
Post Options Post Options   Quote LowOrbit Quote  Post ReplyReply Direct Link To This Post Posted: 14-Jun-2013 at 9:39am
In thinking about this more, this may be one of those cases where async is not appropriate. The DeletegateCommand's CanExecute is basically asking the question, "Can this method be executed?". If a method "could" be executed asyncronously, you have no idea on when the answer can be returned. This would have the effect of your button/menu/control being enabled/disabled at random times depending upon how long it takes for the async method to complete.
 
The effect of this could be confusing, for example, if a menu item suddenly disables itself a few seconds after being displayed.
 
So I guess I'm looking for a little guidance on how to handle this scenario? I am using Cocktail and the UnitOfWork stuff. All queries are executed asyncronously. How would I execute the query and get the answer back to the delegatecommand when forced to do queries asyncronously?
 
Thanks!
Back to Top
mgood View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 18-Nov-2010
Location: Emeryville, CA
Posts: 583
Post Options Post Options   Quote mgood Quote  Post ReplyReply Direct Link To This Post Posted: 14-Jun-2013 at 1:34pm
That's what INotifyPropertyChanged is all about. You let the view know to refresh the binding once you you performed your async work.

Button states typically get initialized during VM initialization and may change in response to a user action. Both can be asynchronous. Enabling/Disabling should trigger a NotifyPropertyChanged in the Command so that the view refreshes the binding. 

You simply perform your asynchronous query in response to a user action or during VM initialization and once the result comes back you enable/disable the command. You would typically disable all commands in the ctor, so that the user can't click anything until the view model is properly initialized and the appropriate buttons light up. 

BTW, why are you using the DelegateCommand instead of Caliburn.Micro actions? 

The following VM is somewhat of a good representation of what I'm talking about. Notice how UpdateCommands() is called in the appropriate places after something happens in the application and then UpdateCommands fires NotifyProperty changes on the various CanXXX properties to refresh the binding and have the appropriate buttons light up. 


The CanXXX doesn't need to be asynchronous. What matters is that you trigger a NotifyPropertyChanged when necessary, so the view triggers a reevaluation of the appropriate CanXXX properties.
Back to Top
LowOrbit View Drop Down
Newbie
Newbie


Joined: 17-Aug-2007
Location: United States
Posts: 20
Post Options Post Options   Quote LowOrbit Quote  Post ReplyReply Direct Link To This Post Posted: 14-Jun-2013 at 2:20pm
I started down the DelegateCommand route and have since changed to the Caliburn.Micro way.
 
But I still have the same problem. In the CanXX methods, I need to fetch data from the database via the UnitOfWork and return a boolean. The return value of these CanXX methods is a bool. I have to await the fetch from the database in order to return the proper value which means putting async on the method.
 
You are not allowed to have a method defined as      async bool. You have to change it to "async Task" or "async Task<xx>". The DeletegateCommand CanExecute cannot point to this kind of method (hence the original question). Will the Caliburn.Micro CanXX version of a method defined as "async Task<bool>" work properly?
 
Thanks
Robert
Back to Top
mgood View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 18-Nov-2010
Location: Emeryville, CA
Posts: 583
Post Options Post Options   Quote mgood Quote  Post ReplyReply Direct Link To This Post Posted: 14-Jun-2013 at 2:29pm
CanXXX gets bound to the Enabled property on the corresponding XAML control. That can't be asynchronous. I think you've got something upside down here. There should not be a need to query in a CanXXX method at all. You should do this query in Initialize and/or in response to an action that might change the result of that query. Store the boolean result in a private field that is returned by CanXXX. After running the query you call NotifyOfPropertyChange(x => CanXXX) to have the view reevaluate the binding. 
Back to Top
LowOrbit View Drop Down
Newbie
Newbie


Joined: 17-Aug-2007
Location: United States
Posts: 20
Post Options Post Options   Quote LowOrbit Quote  Post ReplyReply Direct Link To This Post Posted: 14-Jun-2013 at 2:39pm
Ok, I understand. I was executing the CanXX on a ContextMenu in this case. Since this method usually only gets executed when the menu is about to be displayed, I was hoping to save a trip to the database.
 
Thanks!
Back to Top
 Post Reply Post Reply

Forum Jump Forum Permissions View Drop Down