How to use CanExecute with Mvvmcross

I have a button

<Button android:id="@+id/ButtonConnect" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Disconnect" local:MvxBind="{'Click':{'Path':'DisconnectCommand'}}" /> 

And I have a team for him

 public IMvxCommand DisconnectCommand { get { return new MvxRelayCommand(this.GetService<IConnectionService>().Disconnect); } } 

Then I want to enable / disable DisconnectCommand using

 DisconnectCommand.CanExecute(this.GetService<IConnectionService>().UsbConnected); 

But this is clearly wrong (it doesn't work), I put the check as a parameter, but usually I would do

 DisconnectCommand.CanExecute = someBool; 

But there is no property to install, so how to do it?

+7
source share
2 answers

To learn how to use CanExecute , take a look at Silverlight or WPF - there are many blogs that talk about how to use ICommand - for example. http://weblogs.asp.net/nmarun/archive/2009/12/02/using-icommand-silverlight-4.aspx or http://blog.galasoft.ch/archive/2009/09/26/using- relaycommands-in-silverlight-and-wpf.aspx

An example would be something like:

 private MvxRelayCommand _disconnectCommand; public IMvxCommand DisconnectCommand { get { if (_disconnectCommand == null) _disconnectCommand = new MvxRelayCommand(this.GetService<IConnectionService>().Disconnect, item => this.IsItemConnected(item)); return _disconnectCommand; } } private void SomeServiceNotificationHandler() { _disconnectCommand.RaisePropertyChanged(); } private bool IsItemConnected(object thing) { return /* your code */; } 

There is one small problem though ....

CanExecute is actually not fully implemented in all MvxBindings on all platforms ... It will work for some of them, but for some of them it will not - and I really don't know which ones are currently! If you encounter problems, then please let me know (via GitHub questions), and they will be fixed ...


Personally ... I am not inclined to use CanExecute - instead, I prefer to use a separate boolean property, which then binds to any property available on the control. most controls have something like Enabled , IsEnabled , Disabled , IsDisabled , etc.

I usually find it easier (and easier to read) to set a boolean property rather than calling RaiseCanExecuteChanged

eg. I would use something like:

 <Button android:id="@+id/ButtonConnect" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Disconnect" local:MvxBind="{'Click':{'Path':'DisconnectCommand'},'Enabled':{'Path':'UsbConnected'}}" /> 

You can definitely argue that the CanExecute approach has its advantages - because it stores Command logic in a single object and because it can be used to prevent Execute calls that occur inside RelayCommand . That's why I am happy to try to fix CanExecute errors in mvvmcross bindings when we find them.

+7
source

To follow Stuartโ€™s response, itโ€™s easy to support both ICommand.CanExecute and set properties to support Mvx bindings from Android and iOS.

To do this, convert your typical CanExecute( ) methods to properties, and then add handlers to CanExecuteChanged , which calls RaisePropertyChanged in the associated property. Then use RaiseCanExecuteChanged as usual, and the PropertyChanged event will also RaiseCanExecuteChanged .

  ... // constructor public SomeClass() { DoSomethingCommand = new MvxCommand(OnDoSomething, () => CanDoSomething); DoSomethingCommand .CanExecuteChanged += (sender, args) => RaisePropertyChanged(() => CanDoSomething); } public bool CanDoSomething { get { ... } } ... 
+3
source

All Articles