lbugnion / mvvmlight

The main purpose of the toolkit is to accelerate the creation and development of MVVM applications in Xamarin.Android, Xamarin.iOS, Xamarin.Forms, Windows 10 UWP, Windows Presentation Foundation (WPF), Silverlight, Windows Phone.
http://www.mvvmlight.net
MIT License
1.17k stars 312 forks source link

RelayCommand.RaiseCanExecuteChanged() does nothing under Xamarin #46

Open AndrueCope opened 6 years ago

AndrueCope commented 6 years ago

We are porting some WPF code to Xamarin and at one point we have the following method:

public void RaiseCanExecuteChanged() { foreach (var cmd in _relayCommands) { cmd.RaiseCanExecuteChanged(); } }

This works fine under WPF but under Xamarin the exact same code (it's a shared assembly) does nothing. None of the command's canExecute() methods are called. The methods are being called when first binding to the commands but we can't call them after that :-/

olitee commented 6 years ago

I know under WPF the cmd.RaiseCanExecuteChanged() method must be called from the UI thread. If it isn't, no exception is thrown - but the binding engine doesn't react (or call CanExecute()). Are you sure your ported version is calling that method from the main/UI thread?

AndrueCope commented 6 years ago

Yes. It's being called from a lambda that is passed to Xamarin.Forms.Device.BeginInvokeOnMainThread(). I worked around it by calling PropertyChanged for each bound command instead:

foreach (var prop in GetType().GetProperties().Where(p => p.PropertyType == typeof(ICommand))) { RaisePropertyChanged(prop.Name); } The commands don't actually change but that seems to cause Xamarin to call CanExecute() anyway. Also I don't know if this is relevant but I can step into RaiseCanExecuteChanged() with WPF but with mobile I can't.

StephanBis commented 5 years ago

@olitee is correct, I had to run the RaiseCanExecuteChanged on the UI thread and it worked as expected afterwards.

Device.BeginInvokeOnMainThread(() => {
    ((RelayCommand) MyCommand).RaiseCanExecuteChanged();
});