Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ObservableProperty with NotifyCanExecuteChangedFor exception occurs #858

Open
TSKHot opened this issue Apr 4, 2024 · 0 comments
Open

ObservableProperty with NotifyCanExecuteChangedFor exception occurs #858

TSKHot opened this issue Apr 4, 2024 · 0 comments
Labels
bug 🐛 An unexpected issue that highlights incorrect behavior

Comments

@TSKHot
Copy link

TSKHot commented Apr 4, 2024

Describe the bug

With a very simple piece of code an exception is raised within the toolkit generated CanExecuteChanged method.

Regression

No response

Steps to reproduce

Very simple page (supposed to be an account registration page, but cut right back to the bare bones for illustrating the issue)

 xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
             x:Class="WalletApp.Views.RegisterPage"
             x:DataType="viewModel:RegisterViewModel"
             xmlns:viewModel="clr-namespace:WalletApp.ViewModels"
             xmlns:helpers="clr-namespace:WalletApp.Helpers"
             Title="{Binding Title}">

    <VerticalStackLayout Style="{StaticResource BaseLayout}">

        <ActivityIndicator IsRunning="{Binding IsBusy}"/>
        
        <StackLayout Orientation="Horizontal">
            <Image Source="{AppThemeBinding Light=user_icon.png, Dark=user_icon_dark.png}" Style="{StaticResource EntryIcon}" />
            <Entry x:Name="UserNameEntry" Text="{Binding Username}" Placeholder="User name" IsEnabled="{Binding IsBusy, Converter={helpers:InverseBoolConverter}}" Style="{StaticResource Default}">
                <Entry.Behaviors>
                    <toolkit:UserStoppedTypingBehavior 
                        Command="{Binding UsernameCheckCommand}"
                        StoppedTypingTimeThreshold="500"
                        MinimumLengthThreshold="5"
                        ShouldDismissKeyboardAutomatically="True"/>
                </Entry.Behaviors>
            </Entry>
        </StackLayout>

        <Button x:Name="RegisterButton" Command="{Binding RegisterCommand}" Text="Register" />

    </VerticalStackLayout>
</ContentPage>
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;


namespace WalletApp.ViewModels
{
    public partial class RegisterViewModel : BaseViewModel
    {

        [ObservableProperty]
        [NotifyCanExecuteChangedFor(nameof(RegisterCommand))]
        private string _username;

        [NotifyCanExecuteChangedFor(nameof(RegisterCommand))]
        [ObservableProperty]
        private bool _accountExists;

        public RegisterViewModel()
        {

            Title = "Register";

            Username = string.Empty;
            AccountExists = false;
        }

        [RelayCommand]
        private async Task UsernameCheck()
        {
            try
            {
                AccountExists = true;
            }
            catch (Exception ex)
            {
                Console.Write(ex);
            }
        }


        private bool CheckCanRegister()
        {
            return !AccountExists;
        }

        [RelayCommand(CanExecute = nameof(CheckCanRegister))]
        public async Task Register()
        {
            var registered = true;
        }
    }
}
namespace WalletApp.ViewModels
{
    public partial class BaseViewModel : ObservableValidator
    {
        [ObservableProperty]
        private bool _isBusy;

        [ObservableProperty]
        private string _title;
    }
}

Setting the value of AccountExists to true in the UsernameCheck function consistently throws an exception. Note, setting the value to false does not cause the exception.

[DOTNET] Android.Util.AndroidRuntimeException: Only the original thread that created a view hierarchy can touch its views.
[DOTNET] at Java.Interop.JniEnvironment.InstanceMethods.CallNonvirtualVoidMethod(JniObjectReference instance, JniObjectReference type, JniMethodInfo method, JniArgumentValue* args) in /Users/runner/work/1/s/xamarin-android/external/Java.Interop/src/Java.Interop/obj/Release/net7.0/JniEnvironment.g.cs:line 20830
[DOTNET] at Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeVirtualVoidMethod(String encodedMember, IJavaPeerable self, JniArgumentValue* parameters) in /Users/runner/work/1/s/xamarin-android/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods_Invoke.cs:line 75
[DOTNET] at Android.Views.View.set_Background(Drawable value) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/obj/Release/net8.0/android-34/mcw/Android.Views.View.cs:line 5617
[DOTNET] at Microsoft.Maui.Platform.ButtonExtensions.UpdateBorderDrawable(MaterialButton platformView, IButton button) in D:\a_work\1\s\src\Core\src\Platform\Android\ButtonExtensions.cs:line 80
[DOTNET] at Microsoft.Maui.Platform.ButtonExtensions.UpdateBackground(MaterialButton platformView, IButton button) in D:\a_work\1\s\src\Core\src\Platform\Android\ButtonExtensions.cs:line 11
[DOTNET] at Microsoft.Maui.Handlers.ButtonHandler.MapBackground(IButtonHandler handler, IButton button) in D:\a_work\1\s\src\Core\src\Handlers\Button\ButtonHandler.Android.cs:line 71
[DOTNET] at Microsoft.Maui.PropertyMapper2.<>c__DisplayClass5_0[[Microsoft.Maui.IButton, Microsoft.Maui, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[Microsoft.Maui.Handlers.IButtonHandler, Microsoft.Maui, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].<Add>b__0(IElementHandler h, IElement v) in D:\a\_work\1\s\src\Core\src\PropertyMapper.cs:line 172 [DOTNET] at Microsoft.Maui.PropertyMapper.UpdatePropertyCore(String key, IElementHandler viewHandler, IElement virtualView) in D:\a\_work\1\s\src\Core\src\PropertyMapper.cs:line 47 [DOTNET] at Microsoft.Maui.PropertyMapper.UpdateProperty(IElementHandler viewHandler, IElement virtualView, String property) in D:\a\_work\1\s\src\Core\src\PropertyMapper.cs:line 72 [DOTNET] at Microsoft.Maui.Handlers.ElementHandler.UpdateValue(String property) in D:\a\_work\1\s\src\Core\src\Handlers\Element\ElementHandler.cs:line 87 [DOTNET] at Microsoft.Maui.Controls.VisualElement.MapBackgroundColor(IViewHandler handler, IView view) in D:\a\_work\1\s\src\Controls\src\Core\VisualElement\VisualElement.Mapper.cs:line 42 [DOTNET] at Microsoft.Maui.PropertyMapperExtensions.<>c__DisplayClass2_02[[Microsoft.Maui.IView, Microsoft.Maui, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[Microsoft.Maui.IViewHandler, Microsoft.Maui, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].b__0(IViewHandler h, IView v, Action2 p) in D:\a\_work\1\s\src\Core\src\PropertyMapperExtensions.cs:line 66 [DOTNET] at Microsoft.Maui.PropertyMapperExtensions.<>c__DisplayClass1_02[[Microsoft.Maui.IView, Microsoft.Maui, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[Microsoft.Maui.IViewHandler, Microsoft.Maui, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].g__newMethod|0(IElementHandler handler, IElement view) in D:\a_work\1\s\src\Core\src\PropertyMapperExtensions.cs:line 46
[DOTNET] at Microsoft.Maui.PropertyMapper`2.<>c__DisplayClass5_0[[Microsoft.Maui.IView, Microsoft.Maui, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[Microsoft.Maui.IViewHandler, Microsoft.Maui, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].b__0(IElementHandler h, IElement v) in D:\a_work\1\s\src\Core\src\PropertyMapper.cs:line 172
[DOTNET] at Microsoft.Maui.PropertyMapper.UpdatePropertyCore(String key, IElementHandler viewHandler, IElement virtualView) in D:\a_work\1\s\src\Core\src\PropertyMapper.cs:line 47
[DOTNET] at Microsoft.Maui.PropertyMapper.UpdateProperty(IElementHandler viewHandler, IElement virtualView, String property) in D:\a_work\1\s\src\Core\src\PropertyMapper.cs:line 72
[DOTNET] at Microsoft.Maui.Handlers.ElementHandler.UpdateValue(String property) in D:\a_work\1\s\src\Core\src\Handlers\Element\ElementHandler.cs:line 87
[DOTNET] at Microsoft.Maui.Controls.Element.OnPropertyChanged(String propertyName) in D:\a_work\1\s\src\Controls\src\Core\Element\Element.cs:line 573
[DOTNET] at Microsoft.Maui.Controls.Button.OnPropertyChanged(String propertyName) in D:\a_work\1\s\src\Controls\src\Core\Button\Button.cs:line 472
[DOTNET] at Microsoft.Maui.Controls.BindableObject.SetValueActual(BindableProperty property, BindablePropertyContext context, Object value, Boolean currentlyApplying, SetValueFlags attributes, SetterSpecificity specificity, Boolean silent) in D:\a_work\1\s\src\Controls\src\Core\BindableObject.cs:line 641
[DOTNET] at Microsoft.Maui.Controls.BindableObject.SetValueCore(BindableProperty property, Object value, SetValueFlags attributes, SetValuePrivateFlags privateAttributes, SetterSpecificity specificity) in D:\a_work\1\s\src\Controls\src\Core\BindableObject.cs:line 569
[DOTNET] at Microsoft.Maui.Controls.AppThemeBinding.<>c__DisplayClass9_0.g__Set|0() in D:\a_work\1\s\src\Controls\src\Core\AppThemeBinding.cs:line 86
[DOTNET] at Microsoft.Maui.Controls.AppThemeBinding.ApplyCore(Boolean dispatch) in D:\a_work\1\s\src\Controls\src\Core\AppThemeBinding.cs:line 72
[DOTNET] at Microsoft.Maui.Controls.AppThemeBinding.Apply(Object context, BindableObject bindObj, BindableProperty targetProperty, Boolean fromBindingContextChanged, SetterSpecificity specificity) in D:\a_work\1\s\src\Controls\src\Core\AppThemeBinding.cs:line 46
[DOTNET] at Microsoft.Maui.Controls.BindableObject.SetBinding(BindableProperty targetProperty, BindingBase binding, SetterSpecificity specificity) in D:\a_work\1\s\src\Controls\src\Core\BindableObject.cs:line 332
[DOTNET] at Microsoft.Maui.Controls.Setter.Apply(BindableObject target, SetterSpecificity specificity) in D:\a_work\1\s\src\Controls\src\Core\Setter.cs:line 75
[DOTNET] at Microsoft.Maui.Controls.VisualStateManager.GoToState(VisualElement visualElement, String name) in D:\a_work\1\s\src\Controls\src\Core\VisualStateManager.cs:line 111
[DOTNET] at Microsoft.Maui.Controls.VisualElement.ChangeVisualState() in D:\a_work\1\s\src\Controls\src\Core\VisualElement\VisualElement.cs:line 1482
[DOTNET] at Microsoft.Maui.Controls.View.ChangeVisualState() in D:\a_work\1\s\src\Controls\src\Core\View\View.cs:line 196
[DOTNET] at Microsoft.Maui.Controls.Button.ChangeVisualState() in D:\a_work\1\s\src\Controls\src\Core\Button\Button.cs:line 370
[DOTNET] at Microsoft.Maui.Controls.VisualElement.OnIsEnabledPropertyChanged(BindableObject bindable, Object oldValue, Object newValue) in D:\a_work\1\s\src\Controls\src\Core\VisualElement\VisualElement.cs:line 1554
[DOTNET] at Microsoft.Maui.Controls.BindableObject.SetValueActual(BindableProperty property, BindablePropertyContext context, Object value, Boolean currentlyApplying, SetValueFlags attributes, SetterSpecificity specificity, Boolean silent) in D:\a_work\1\s\src\Controls\src\Core\BindableObject.cs:line 643
[DOTNET] at Microsoft.Maui.Controls.BindableObject.SetValueCore(BindableProperty property, Object value, SetValueFlags attributes, SetValuePrivateFlags privateAttributes, SetterSpecificity specificity) in D:\a_work\1\s\src\Controls\src\Core\BindableObject.cs:line 569
[DOTNET] at Microsoft.Maui.Controls.BindableObject.SetValue(BindableProperty property, Object value, SetterSpecificity specificity) in D:\a_work\1\s\src\Controls\src\Core\BindableObject.cs:line 503
[DOTNET] at Microsoft.Maui.Controls.BindableObjectExtensions.RefreshPropertyValue(BindableObject self, BindableProperty property, Object value) in D:\a_work\1\s\src\Controls\src\Core\BindableObjectExtensions.cs:line 26
[DOTNET] at Microsoft.Maui.Controls.VisualElement.RefreshIsEnabledProperty() in D:\a_work\1\s\src\Controls\src\Core\VisualElement\VisualElement.cs:line 1645
[DOTNET] at Microsoft.Maui.Controls.Button.Microsoft.Maui.Controls.Internals.ICommandElement.CanExecuteChanged(Object sender, EventArgs e) in D:\a_work\1\s\src\Controls\src\Core\Button\Button.cs:line 463
[DOTNET] at CommunityToolkit.Mvvm.Input.AsyncRelayCommand.NotifyCanExecuteChanged() in /_/src/CommunityToolkit.Mvvm/Input/AsyncRelayCommand.cs:line 267
[DOTNET] at ViewModels.RegisterViewModel.set_AccountExists(Boolean value) in C:\BySapio\Starling\DotNet\RewardsApp\CommunityToolkit.Mvvm.SourceGenerators\CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator\ViewModels.RegisterViewModel.g.cs:line 49
[DOTNET] at ViewModels.RegisterViewModel.UsernameCheck() in C:\BySapio\Starling\DotNet\RewardsApp\ViewModels\RegisterViewModel.cs:line 34
[DOTNET] --- End of managed Android.Util.AndroidRuntimeException stack trace ---



### Expected behavior

No exception should be thrown.

### Screenshots

_No response_

### IDE and version

VS 2022

### IDE version

17.9.5

### Nuget packages

- [ ] CommunityToolkit.Common
- [ ] CommunityToolkit.Diagnostics
- [ ] CommunityToolkit.HighPerformance
- [X] CommunityToolkit.Mvvm (aka MVVM Toolkit)

### Nuget package version(s)

8.2.2

### Additional context

Also using CommunityToolkit.Maui 7.0.1

### Help us help you

No, just wanted to report this
@TSKHot TSKHot added the bug 🐛 An unexpected issue that highlights incorrect behavior label Apr 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug 🐛 An unexpected issue that highlights incorrect behavior
Projects
None yet
Development

No branches or pull requests

1 participant