3

Description

Hello,

Rendering of Layouts are not updated if they contains controls (ContentView) with some rendering Task !

  1. I created a simple ContentView which contains three Image (the FireControl in the screenshot).
  2. In the constructor, I use a simple async method, with Task.Factory.StartNew, which will play on the visibility of the Face images with a small Task.Delay between them.
  3. In the MainPage, I load this control in a StackLayout, using a button : "Load control".
  • It is impossible for me to add a second control (if I press again "Load control" )!
  • It's like if the rendering of the StackLayout in my MainPage was not updated ...
  • If I dont call my task method: no rendering problem!
  • If I dont touch controls in my task method: no rendering problem !
  • If I spam-click "Load control" and "Remove control", sometimes loaded controls appears...

Is there a way to tell my StackLayout to update its rendering after adding a control? Is there a better way than Task.Factory.StartNew to perform frame animation in a control, so as not to block the rendering? (In this example the desired animation has been simplified)

Steps to Reproduce

My Test solution : Test Solution

TestControl

    public class TestControl : ContentView
    {
        protected Image FaceNormal;
        protected Image FaceLoose;
    
        public TestControl()
        {
            var principalImage = new Image { Source = "fire_principal.png" }; // The body
            FaceNormal = new Image { Source = "fire_facenormal.png" }; // Opened eyes
            FaceLoose = new Image { Source = "fire_faceloose.png" }; // Closed eyes
            Content = new Grid { Children = { principalImage, FaceNormal, FaceLoose } }; // Loaded in the Content
           
           // /!\ Causes rendering errors in the StackLayout
            Task.Factory.StartNew(() => StartFaceAnimation());
        }
    
        public async Task StartFaceAnimation()
        {
            Dispatcher.Dispatch(() =>
            {
                FaceNormal.IsVisible = true;
                FaceLoose.IsVisible = false;
            });
            await Task.Delay(2000);
            Dispatcher.Dispatch(() =>
            {
                FaceNormal.IsVisible = false;
                FaceLoose.IsVisible = true;
            });
        }
    }

MainPage

    public class MainPage : ContentPage
    {
        public MainPage()
        {
            var verticalStackLayout = new VerticalStackLayout();
    
            var loadTestControlButton = new Button { Text = "Load control", Margin = 2 }; 
            loadTestControlButton.Clicked += (o, e) => verticalStackLayout.Children.Add(new TestControl()); 
            verticalStackLayout.Children.Add(loadTestControlButton);
            
            var removeTestControlButton = new Button { Text = "Remove control", Margin = 2 }; 
            removeTestControlButton.Clicked += (o, e) => verticalStackLayout.Children.Remove(verticalStackLayout.Children.Last()); 
            verticalStackLayout.Children.Add(removeTestControlButton);
    
            Content = verticalStackLayout;
        }
    }
SpaaJ
  • 61
  • 6
  • VS' current Maui build has [severe layout updating issues on Android](https://github.com/dotnet/maui/issues/8044). Changing visibility of items is one way to see the layout not work. The recent change that broke stuff is rolled back in the next release. See linked issue for how to obtain nightly build, or alternatively to refer to the release before this one. Or wait for next release later this month. A work-around for testing is `MainPage = new MyPage();` (or navigate route again, for AppShell) + static variables. E.g. in constructor: `InitializeComponent(); FaceNormal.IsVisible = sVis1; ...` – ToolmakerSteve Jul 02 '22 at 23:50
  • Thank you, but I need to create and delete a lot of TestControls, icannot create static variable for each contols :( I will see on [severe layout updating issues on Android](https://github.com/dotnet/maui/issues/8044) – SpaaJ Jul 03 '22 at 13:20

1 Answers1

1

The trick is to call Arrange after IsVisible, see the below modifications:

public async Task StartFaceAnimation()
    {
        Dispatcher.Dispatch(() =>
        {
            FaceNormal.IsVisible = true;
            FaceLoose.IsVisible = false;
            Arrange(new Rect());
        });
        await Task.Delay(2000);
        Dispatcher.Dispatch(() =>
        {
            FaceNormal.IsVisible = false;
            FaceLoose.IsVisible = true;
            Arrange(new Rect());
        });
    }

It redraws the controls!

SpaaJ
  • 61
  • 6
  • Good, glad that worked - All the tests I did indicated that if layout wasn't automatically working, it was because layout arrangement was broken, so forcing it wouldn't work. – ToolmakerSteve Jul 03 '22 at 18:11
  • Could you please mark it as an accepted answer? This will help more people which meet the same problem. – Liyun Zhang - MSFT Jul 22 '22 at 08:36