简体   繁体   English

使用任务修改控件时布局呈现错误

[英]Layout render error when using Tasks modifying controls

Description描述

Hello,你好,

Rendering of Layouts are not updated if they contains controls (ContentView) with some rendering Task !如果布局包含带有一些渲染任务的控件(ContentView),则不会更新布局的渲染!

  1. I created a simple ContentView which contains three Image (the FireControl in the screenshot).我创建了一个简单的 ContentView,其中包含三个 Image(屏幕截图中的 FireControl)。
  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.在构造函数中,我使用了一个简单的异步方法,带有 Task.Factory.StartNew,它将在人脸图像的可见性上播放,它们之间有一个小的 Task.Delay。
  3. In the MainPage, I load this control in a StackLayout, using a button : "Load control".在 MainPage 中,我使用一个按钮将这个控件加载到 StackLayout 中:“加载控件”。
  • 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 ...就像我的 MainPage 中 StackLayout 的渲染没有更新一样......
  • 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?有没有办法告诉我的 StackLayout 在添加控件后更新其渲染? Is there a better way than Task.Factory.StartNew to perform frame animation in a control, so as not to block the rendering?有没有比 Task.Factory.StartNew 更好的方法在控件中执行帧动画,以免阻塞渲染? (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;
        }
    }

The trick is to call Arrange after IsVisible, see the below modifications:诀窍是在 IsVisible 之后调用 Arrange,请参阅以下修改:

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!它重绘控件!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM