dotnet / maui

.NET MAUI is the .NET Multi-platform App UI, a framework for building native device applications spanning mobile, tablet, and desktop.
https://dot.net/maui
MIT License
22.16k stars 1.74k forks source link

Setting HeightRequest programmatically not working if performed too early #11789

Open riccardominato opened 1 year ago

riccardominato commented 1 year ago

Description

I have an issue trying to make a circular Ellipse without knowing height and width in advance. I'm assuming it fills horizontally its parent.

I hoped this worked.

<Ellipse
    x:Name="Circle"
    Fill="Blue"
    HeightRequest="{Binding Source={RelativeSource Self}, Path=Width}"
    />

First of all, this is not the HeightRequest is not guaranteed to be respected because it's only a request kind of problem, because if I set it without Binding it works. It actually works even with Binding, if I trigger the Hot Reload on HeightRequest.

Furthermore, it didn't work even trying to set HeightRequest from code-behind.

public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();

        Circle.PropertyChanged += Circle_PropertyChanged;
    }

    private void Circle_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        if (e.PropertyName == "Width")
        {
            Circle.HeightRequest = Circle.Width;
        }
    }
}

This issue seems to be caused by trying to change HeightRequest as soon as the component is created, because if I set a delay before (as you can see in the workaround) or try to change it in response to a button click, it works as expected.

Steps to Reproduce

  1. Create a component in .NET MAUI app
  2. Set HeightRequest with binding or from code-behind when the component is created.

Expected result e0dc4ac9-e92a-4d72-baf7-9c5270cf3be1

Actual result f52126d9-c6d0-476f-93dc-fa8717d46920

Link to public reproduction project repository

https://github.com/Riccardo11/MauiHeightRequestIssue

Version with bug

7.0 (current)

Last version that worked well

Unknown/Other

Affected platforms

Android

Affected platform versions

Android 9 (couldn't test others)

Did you find any workaround?

A workaround is to set a delay, even minimal, before changing HeightRequest from code behind.

private async void Circle_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
    if (e.PropertyName == "Width")
    {
        await Task.Delay(1);  // this is necessary!!
        Circle.HeightRequest = Circle.Width;
    }
}

Relevant log output

No response

ghost commented 1 year ago

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

riccardominato commented 1 year ago

Maybe it can be helpful to know that it seems this was a problem with Xamarin.Forms, too. Check this StackOverflow question.

BetaDeltic commented 1 year ago

I ran into the same issue with Grid and Android 10. Works fine on Windows.

Zhanglirong-Winnie commented 1 year ago

Verified this issue with Visual Studio 17.7.0 Preview 1.0. Can repro on android platform with sample project. MauiHeightRequestIssue-main.zip Screenshot 2023-06-01 170615

datvm commented 1 month ago

I have this issue from an event as well so the "too early" is not even applicable. This is the code:

    private void Maps_WindowHeightChanged(double height)
    {
        Dispatcher.Dispatch(() =>
        {
            blazorWebView.HeightRequest = height;
            ForceLayout();
        });
    }

No matter what I do, the control wouldn't get its new height. I tried with Dispatcher.Dispatch, MainThread.BeginInvokeOnMainThread or just call it directly from the event handler (though this is risky as I think it may get called from outside the UI Thread). Now if I run with Debugger attached and Hot Reload enabled, if I change the number using the Live Property window, the control get to the desired height correctly. Do you know what method is called to ensure it?


UPDATE: this works for me

    private async void Maps_WindowHeightChanged(double height)
    {
        await Dispatcher.DispatchAsync(async () =>
        {
            blazorWebView.HeightRequest = height;
            await Task.Delay(1);
            ForceLayout();
        });
    }