Quantcast
Channel: Xamarin.Forms — Xamarin Community Forums
Viewing all articles
Browse latest Browse all 58056

Should we have to raise ICommand.CanExecuteChanged on the UI thread?

$
0
0

One of the main benefits of MVVM / data binding is that we only have to update our view model properties and the UI 'magically' updates itself as required. This completely removes the necessity to constantly marshal to the UI thread as we're not touching UI (View) methods and properties ourselves.

However, I have found that about 50% of the time I rause the ICommand.CanExecuteChanged event it will cause a native android.view.ViewRootImpl$CalledFromWrongThreadException to be thrown.

The native exception and stack trace is:

Android.Util.AndroidRuntimeException: Exception of type 'Android.Util.AndroidRuntimeException' was thrown.
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6845)
at android.view.ViewRootImpl.invalidateChildInParent(ViewRootImpl.java:1053)
at android.view.ViewGroup.invalidateChild(ViewGroup.java:4531)
at android.view.View.invalidate(View.java:11663)
at android.widget.TextView.invalidateDrawable(TextView.java:5942)
at android.graphics.drawable.DrawableContainer.invalidateDrawable(DrawableContainer.java:286)
at android.graphics.drawable.Drawable.invalidateSelf(Drawable.java:376)
at android.graphics.drawable.Drawable.setVisible(Drawable.java:607)
at android.graphics.drawable.DrawableContainer.selectDrawable(DrawableContainer.java:345)
at android.graphics.drawable.StateListDrawable.onStateChange(StateListDrawable.java:106)
at android.graphics.drawable.Drawable.setState(Drawable.java:523)
at android.view.View.drawableStateChanged(View.java:15967)
at android.widget.TextView.drawableStateChanged(TextView.java:4302)
at android.view.View.refreshDrawableState(View.java:15981)
at android.view.View.setEnabled(View.java:6301)
at android.widget.TextView.setEnabled(TextView.java:1968)
at dalvik.system.NativeStart.run(Native Method)

And the managed stack trace (from Visual Studio) is:

0x63 in Android.Runtime.JNIEnv.CallVoidMethod at /Users/builder/data/lanes/monodroid-mlion-monodroid-4.14-series/a5d57087/source/monodroid/src/Mono.Android/src/Runtime/JNIEnv.g.cs:507,5 C#
0x66 in Android.Views.View.set_Enabled at /Users/builder/data/lanes/monodroid-mlion-monodroid-4.14-series/a5d57087/source/monodroid/src/Mono.Android/platforms/android-19/src/generated/Android.Views.View.cs:4432,6 C#
0x11 in Xamarin.Forms.Platform.Android.ButtonRenderer.UpdateEnabled C#
0x59 in Xamarin.Forms.Platform.Android.ButtonRenderer.OnElementPropertyChanged C#
0x12 in Xamarin.Forms.BindableObject.OnPropertyChanged C#
0xA3 in Xamarin.Forms.BindableObject.SetValueActual C#
0x213 in Xamarin.Forms.BindableObject.SetValueCore C#
0xF in Xamarin.Forms.Button.set_IsEnabledCore C#
0x17 in Xamarin.Forms.Button.CommandCanExecuteChanged C#
0x7 in Xyz.Utility.ActionCommand.b__0 at ...

(Where Xyz.Utility is part of a customer-specific utility library implementing ICommand.)

So, should we have to wrap raising the ICommand.CanExecuteChanged event in a call to Device.BeginInvokeOnMainThread()?

I guess what I'm really asking is whether it should be the responsibility of the app developer to do this, or whether Xamarin.Forms should do this internally in the Button.CommandCanExecuteChanged handler, which would mean everyone's ICommand implementation wouldn't have to worry about it! ;-)

Thanks!


Viewing all articles
Browse latest Browse all 58056

Trending Articles