Skip to content
This repository has been archived by the owner on May 1, 2024. It is now read-only.

Height of Entry with data binding incorrect on UWP when Entry in ScrollView in Grid #2172

Closed
johnshardman opened this issue Mar 23, 2018 · 11 comments
Labels
e/5 🕔 5 help wanted We welcome community contributions to any issue, but these might be a good place to start! in-progress This issue has an associated pull request that may resolve it! inactive Issue is older than 6 months and needs to be retested p/UWP t/bug 🐛 up-for-grabs We welcome community contributions to any issue, but these might be a good place to start!

Comments

@johnshardman
Copy link

Bug report best practices: https://github.com/xamarin/Xamarin.Forms/wiki/Submitting-Issues

Description

On complex pages on UWP, the height of Entry views can be incorrect, clipping the bottom of the text in the Entry. This occurs when the Entry uses data binding, and is in a Layout inside a ScrollView inside a Grid.

Steps to Reproduce

Using the following code with Xamarin.Forms 2.4.0.38779, push an instance of the BugUWPEntryBindingPageView page onto the navigation stack. Press the Button that appears at the top of the page and view the Entry that then appears. On UWP, the Entry is clipped.

Then, to see a nasty workaround, change the WorkaroundBug boolean to true and run again.

using System.Threading.Tasks;

using Xamarin.Forms;

namespace ViewsUsingXamarinForms
{
public class BugUWPEntryBindingViewModel : BindableObject
{
public static readonly BindableProperty ValueOneProperty
= BindableProperty.Create(
nameof(ValueOne),
typeof(string),
typeof(BugUWPEntryBindingViewModel),
default(string));

    public static readonly BindableProperty ValueTwoProperty
        = BindableProperty.Create(
            nameof(ValueTwo),
            typeof(string),
            typeof(BugUWPEntryBindingViewModel),
            default(string));

    public BugUWPEntryBindingViewModel()
    {
        ValueTwo = string.Empty;
        ValueOne = "123";
    }

    public string ValueOne
    {
        get => (string) GetValue(ValueOneProperty);

        set
        {
            if (ValueOne != value)
                SetValue(ValueOneProperty, value);
        }
    }

    public string ValueTwo
    {
        get => (string) GetValue(ValueTwoProperty);

        set
        {
            if (ValueTwo != value)
                SetValue(ValueTwoProperty, value);
        }
    }

} // public class BugUWPEntryBindingViewModel

public class BugUWPEntryBindingPageView : ContentPage
{
    private static readonly BugUWPEntryBindingViewModel ViewModel = new BugUWPEntryBindingViewModel();

    private Grid _grid;

    protected override void OnAppearing()
    {
        _grid = new Grid
        {
            BackgroundColor = Color.White,
            HorizontalOptions = LayoutOptions.Fill,
            VerticalOptions = LayoutOptions.FillAndExpand,
            ColumnDefinitions = new ColumnDefinitionCollection
            {
                new ColumnDefinition { Width = GridLength.Star },
            },
            RowDefinitions = new RowDefinitionCollection
            {
                new RowDefinition {Height = GridLength.Auto },
                new RowDefinition {Height = GridLength.Star }
            },
        };

        _grid.Children.Add(
            new Button
            {
                Text = "Add/replace entries",
                BackgroundColor = Color.Blue,
                TextColor = Color.White,
                Command = new Command(OnAddEntries)
            }, 0, 1, 0, 1);

        BindingContext = ViewModel;
        Content = _grid;
    }

    private const bool WorkaroundBug = false;
    private void OnAddEntries()
    {
        string text;
        if (WorkaroundBug)
        {
            text = ViewModel.ValueOne;
            ViewModel.ValueOne = string.Empty;
        }

        Entry entry = new Entry
        {
            FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Entry)),
        };
        entry.SetBinding(
            Entry.TextProperty,
            new Binding(
                nameof(BugUWPEntryBindingViewModel.ValueOne),
                BindingMode.TwoWay,
                null,
                string.Empty));
        _grid.Children.Add(
            new ScrollView
            {
                Content = new StackLayout
                {
                    Children =
                    {
                        entry
                    }
                }
            }, 0, 1, 1, 2);

        if (WorkaroundBug)
        {
            Task.Run(async () =>
            {
                await Task.Delay(1);
                Device.BeginInvokeOnMainThread(() =>
                {
                    ViewModel.ValueOne = text;
                });
            });
        }
    }
}

}

Expected Behavior

Expect to see "123"

Actual Behavior

Expect to see "123" but with bottom of text clipped.

Basic Information

  • Version with issue: 2.4.0.38779
  • Last known good version: N/A
  • IDE: VS2017
  • Platform Target Frameworks:
    • UWP: 14393
  • Nuget Packages: XF 2.4.0.38779
  • Affected Devices: Windows 10 x64 bit desktop

Screenshots

entry

Reproduction Link

@pauldipietro
Copy link
Contributor

Checked against the 3.0.0-pre to verify that the code still reproduces the behavior

@johnshardman
Copy link
Author

@pauldipietro - Is there any updated on this? I've just upgraded from XF 2.4 to 3.2.0.839982 and really wasn't expecting this to still be present (which it is).

@PostImpatica
Copy link

I couldn't use stacklayout or grid but I was able to use flexlayout within a scrollview along with entry boxes.

@samhouts samhouts added inactive Issue is older than 6 months and needs to be retested help wanted We welcome community contributions to any issue, but these might be a good place to start! up-for-grabs We welcome community contributions to any issue, but these might be a good place to start! labels Jul 22, 2019
@MitchBomcanhao
Copy link

This is still an issue on 4.2.0
If an entry has some text added to it, either by binding or just setting the value to something, the entry will be rendered with the height that is required by that text at the DEFAULT size.
If you don't add text to the entry in xaml, it'll render with the correct size for the font size you've set up.

eg:

            <Entry Text="{Binding Number}" />
            <Entry FontSize="25" Text="4" />
            <Entry FontSize="25" />

renders as
image

The first entry, which has not had the font size changed, renders with the correct height for the default font size.
The second entry renders with the same height as the first one, but the actual font size is larger so it clips the content.
The third entry renders with the correct height for its potential content.

additional: the second entry will resize itself if you resize the application window.

@MitchBomcanhao
Copy link

I am now doing a workaround similar to the one mentioned above, but instead of fiddling with the value in the viewmodel, I am changing the font size. this seems like a safer thing to do, and it appears to work.
It is still very very bad that we have to use these workarounds as such basic functionality should always work out of the box.

@bmacombe
Copy link
Contributor

@MitchBomcanhao When are you doing the font size change? Assuming MVVM pattern are you doing it in the view code behind? I've been trying to work around this very annoying issue also. It get's worse the more nested layouts get.

@bmacombe
Copy link
Contributor

bmacombe commented Aug 29, 2019

@jfversluis I was watching your stream on the iOS font attribute issue the other day. I noticed similar code in the UWP Entry renderer to what you were tweaking in the iOS label renderer when the font is updated. I was just half watching while working, so I could be way off base that this is even related to this issue, just throwing out the thought.

bool entryIsDefault = entry.FontFamily == null && entry.FontSize == Device.GetNamedSize(NamedSize.Default, typeof(Entry), true) && entry.FontAttributes == FontAttributes.None;

I've been poking around the UWP code base to see if I could find a start to maybe looking into this issue, but I'm not very familiar with the whole layout process.

@MitchBomcanhao
Copy link

@bmacombe I'll share my workaround tomorrow when I get back to my workstation. It's executed on an override to onbindingcontextchanged in the code behind of the control that includes the entry, and I switch the size to a slightly smaller size, wait and then set it to a larger size. I'm also only doing it on uwp and if the value in the Viewmodel isn't null or empty. Might still suffer from timing issues, but less troublesome than messing around with the value in the Viewmodel.

@MitchBomcanhao
Copy link

MitchBomcanhao commented Aug 30, 2019

@bmacombe here it goes. not great at all, but might help someone.
I'm setting a flag as the binding context changed code was being hit a few times, and I only wanted to do it once.
The task,run part is a bit ugly :/

protected override void OnBindingContextChanged()
{
    base.OnBindingContextChanged();

    if (Device.RuntimePlatform == Device.UWP && !this.workaroundExecuted && this.BindingContext is TextBoxViewModel vm && !string.IsNullOrEmpty(vm.Text))
    {
        this.workaroundExecuted = true;

        this.TextEntry.FontSize = ContentFontSizeSmall;
        Task.Run(async () => await Task.Delay(75)).ContinueWith( t => Device.InvokeOnMainThreadAsync(() => this.TextEntry.FontSize = ContentFontSizeRegular));
    }
}

@bmacombe
Copy link
Contributor

@MitchBomcanhao Thanks

I was playing around with the XF codebase yesterday, but didn't make much progress. I couldn't quickly modify one of the existing issues in the ControlGallery to replicate it. I only notice the problem when I'm using SfTextLayout control. Could you send the layout you used to create your sample above? I'll trying making a repro work in the control gallery and then see if I can figure out what the issue is, if I can make sense of the layout system.

I'm thinking it has to be something like a timing issue. It's measuring the size of the entry before updating the font or something.

@bmacombe
Copy link
Contributor

This seems like an issue in the UWP code, it's the native measure that is returning the incorrect size

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
e/5 🕔 5 help wanted We welcome community contributions to any issue, but these might be a good place to start! in-progress This issue has an associated pull request that may resolve it! inactive Issue is older than 6 months and needs to be retested p/UWP t/bug 🐛 up-for-grabs We welcome community contributions to any issue, but these might be a good place to start!
Projects
None yet
Development

No branches or pull requests

6 participants