Search code examples
xaml.net-mauimaui-community-toolkit

Maui with CommunityToolkit ObservableProperty not updating while processing


I have a Maui app only running on Android (Zebra Scan-gun).

When I tap a button on the screen the process that runs may take 30 seconds to complete. During those 30 seconds I update the ObservableProperty's value to give updates to the user as processing continues. Currently, the result is that the UI does not refresh until it returns control to the screen.

As I am using CommunityToolkit.Mvvm the SetProperty is called by internal code which I would expect to refresh the UI.

Here's a bits of relevant code:

    using CommunityToolkit.Mvvm.ComponentModel;
    using CommunityToolkit.Mvvm.Input;
    namespace myNamespace 
    {
       public partical class MyClassVM: ObservableObject
       {
            [ObservableProperty]
            string status;
    
            [RelayCommand]
            void DoStuff()
            {
              var myUseCase = new DoStuffUseCase();
              myUseCase.Execute(UpdateStatus)
            }
    
            public void UpdateStatus(string text, bool isThreadRunning)
            {
                Status = text;
            }
       }
    }

Here's the definition of my Execute use case:

    public void Execute(Action<string, bool> callback)
    {
        callback("Begin", true);
        // do stuff which sometimes takes a few seconds
        callback("End", false);
    }

and here's my XAML:

        <Label x:Name="lblStatus" 
               Text="{Binding Status}" 
               HorizontalTextAlignment="Center" 
               FontSize="20" 
               TextColor="DarkRed" 
               FontAttributes="Bold" 
               Margin="0,20,0,0"/>

The result is the user never sees the "Begin" message. Only the End message after the process is complete.


Solution

  • You can try to add async-await for function Execute .

    Based on your code, I did a test , and it works properly on my side.

    Please refer to the following code:

      public partial class MyClassVM: ObservableObject
    {
        [ObservableProperty]
        string status;
    
        //[RelayCommand]
        public MyClassVM()
        {
            var myUseCase = new DoStuffUseCase();
            myUseCase.Execute(UpdateStatus);
          }
    
        public void UpdateStatus(string text, bool isThreadRunning)
        {
            Status = text;
        }
    }
    
    internal class DoStuffUseCase
    {
        public DoStuffUseCase()
        {
        }
    
    // add async-await  here
    
        public async void Execute(Action<string, bool> callback)
        {
            callback("Begin", true);
            // do stuff which sometimes takes a few seconds
            await Task.Delay(3000);
    
            callback("End", false);
        }
    }