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

[UWP] Attempt to resolve entry on UWP not correctly calculating the correct height when in a scroll view #8214

Merged
merged 21 commits into from
Jan 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 108 additions & 1 deletion Xamarin.Forms.ControlGallery.WindowsUniversal/CustomRenderers.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System.ComponentModel;
using System;
using System.ComponentModel;
using System.Linq;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
Expand All @@ -12,6 +14,8 @@
[assembly: ExportRenderer(typeof(Issue1683.EntryKeyboardFlags), typeof(EntryRendererKeyboardFlags))]
[assembly: ExportRenderer(typeof(Issue1683.EditorKeyboardFlags), typeof(EditorRendererKeyboardFlags))]
[assembly: ExportRenderer(typeof(Issue3273.SortableListView), typeof(SortableListViewRenderer))]
[assembly: ExportRenderer(typeof(Issue2172OldEntry), typeof(Issue2172OldEntryRenderer))]
[assembly: ExportRenderer(typeof(Issue2172OldEditor), typeof(Issue2172OldEditorRenderer))]
namespace Xamarin.Forms.ControlGallery.WindowsUniversal
{
public class EntryRendererKeyboardFlags : EntryRenderer
Expand Down Expand Up @@ -163,4 +167,107 @@ protected override void OnElementChanged(ElementChangedEventArgs<BoxView> e)
m_Canvas.Children.Add(text);
}
}

public class Issue2172OldEntryRenderer : EntryRenderer
{
public override SizeRequest GetDesiredSize(double widthConstraint, double heightConstraint)
{
if (Children.Count == 0 || Control == null)
return new SizeRequest();

var constraint = new Windows.Foundation.Size(widthConstraint, heightConstraint);
FormsTextBox child = Control;

child.Measure(constraint);
var result = new Size(Math.Ceiling(child.DesiredSize.Width), Math.Ceiling(child.DesiredSize.Height));

return new SizeRequest(result);
}
}

public class Issue2172OldEditorRenderer : EditorRenderer
{
static FormsTextBox _copyOfTextBox;
static Windows.Foundation.Size _zeroSize = new Windows.Foundation.Size(0, 0);

FormsTextBox CreateTextBox()
{
return new FormsTextBox
{
AcceptsReturn = true,
TextWrapping = TextWrapping.Wrap,
Style = Windows.UI.Xaml.Application.Current.Resources["FormsTextBoxStyle"] as Windows.UI.Xaml.Style
};
}

/*
* Purely invalidating the layout as text is added to the TextBox will not cause it to expand.
* If the TextBox is set to WordWrap and it is part of the layout it will refuse to Measure itself beyond its established width.
* Even giving it infinite constraints will cause it to always set its DesiredSize to the same width but with a vertical growth.
* The only way I was able to grow it was by setting layout renderers width explicitly to some value but then it just set its own Width to that Width which is not helpful.
* Even vertically it would measure oddly in cases of rapid text changes.
* Holding down the backspace key or enter key would cause the final result to be not quite right.
* Both of these issues were fixed by just creating a static TextBox that is not part of the layout which let me just measure
* the size of the text as it would fit into the TextBox unconstrained and then just return that Size from the GetDesiredSize call.
* */
Size GetCopyOfSize(FormsTextBox control, Windows.Foundation.Size constraint)
{
if (_copyOfTextBox == null)
{
_copyOfTextBox = CreateTextBox();

// This causes the copy to be initially setup correctly.
// I found that if the first measure of this copy occurs with Text then it will just keep defaulting to a measure with no text.
_copyOfTextBox.Measure(_zeroSize);
}

_copyOfTextBox.Text = control.Text;
_copyOfTextBox.FontSize = control.FontSize;
_copyOfTextBox.FontFamily = control.FontFamily;
_copyOfTextBox.FontStretch = control.FontStretch;
_copyOfTextBox.FontStyle = control.FontStyle;
_copyOfTextBox.FontWeight = control.FontWeight;
_copyOfTextBox.Margin = control.Margin;
_copyOfTextBox.Padding = control.Padding;

// have to reset the measure to zero before it will re-measure itself
_copyOfTextBox.Measure(_zeroSize);
_copyOfTextBox.Measure(constraint);

Size result = new Size
(
Math.Ceiling(_copyOfTextBox.DesiredSize.Width),
Math.Ceiling(_copyOfTextBox.DesiredSize.Height)
);

return result;
}


SizeRequest CalculateDesiredSizes(FormsTextBox control, Windows.Foundation.Size constraint, EditorAutoSizeOption sizeOption)
{
if (sizeOption == EditorAutoSizeOption.TextChanges)
{
Size result = GetCopyOfSize(control, constraint);
control.Measure(constraint);
return new SizeRequest(result);
}
else
{
control.Measure(constraint);
Size result = new Size(Math.Ceiling(control.DesiredSize.Width), Math.Ceiling(control.DesiredSize.Height));
return new SizeRequest(result);
}
}

public override SizeRequest GetDesiredSize(double widthConstraint, double heightConstraint)
{
FormsTextBox child = Control;

if (Children.Count == 0 || child == null)
return new SizeRequest();

return CalculateDesiredSizes(child, new Windows.Foundation.Size(widthConstraint, heightConstraint), Element.AutoSize);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
xmlns:controls="clr-namespace:Xamarin.Forms.Controls"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:issues="clr-namespace:Xamarin.Forms.Controls.Issues"
mc:Ignorable="d"
x:Class="Xamarin.Forms.Controls.Issues.Issue2172">
<ContentPage.Content>
<StackLayout>
<Label FontSize="25" Text="Using new measure code, no text should be clipped"></Label>
<ScrollView VerticalScrollBarVisibility="Always">
<Grid BackgroundColor="Green" Padding="5">
<StackLayout>
<StackLayout>
<Entry FontSize="30" Text="{Binding Number}" />
<Entry FontSize="25" Text="Nested" />
<Entry FontSize="25" />
<Label FontSize="25" Text="Label"/>
<Editor FontSize="25" Text="Editor"></Editor>
<Editor FontSize="25" Text="Auto Size Editor, add more lines to test." AutoSize="TextChanges"></Editor>
</StackLayout>
</StackLayout>
</Grid>
</ScrollView>

<BoxView HeightRequest="10" Color="Black"></BoxView>

<Label FontSize="25" Text="Using old measure code, some text should be clipped. Don't resize the window."></Label>
<ScrollView VerticalScrollBarVisibility="Always">
<Grid BackgroundColor="Red" Padding="5">
<StackLayout>
<StackLayout>
<issues:Issue2172OldEntry FontSize="30" Text="{Binding Number}" />
<issues:Issue2172OldEntry FontSize="25" Text="Nested" />
<issues:Issue2172OldEntry FontSize="25" />
<Label FontSize="25" Text="Label"/>
<issues:Issue2172OldEditor FontSize="25" Text="Editor"></issues:Issue2172OldEditor>
<issues:Issue2172OldEditor FontSize="25" Text="Auto Size Editor, add more lines to test." AutoSize="TextChanges"></issues:Issue2172OldEditor>
</StackLayout>
</StackLayout>
</Grid>
</ScrollView>
</StackLayout>

</ContentPage.Content>
</ContentPage>
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;

namespace Xamarin.Forms.Controls.Issues
{
[Preserve(AllMembers = true)]
[Issue(IssueTracker.Github, 2172, "Height of Entry with data binding incorrect on UWP when Entry in ScrollView in Grid", PlatformAffected.UWP)]
public partial class Issue2172 : ContentPage
{
public Issue2172()
{
#if APP
InitializeComponent();
#endif
BindingContext = new Issue2172ViewModel();
}

public class Issue2172ViewModel
{
public string Number => "Bound Text";
}
}

public class Issue2172OldEntry : Entry
{

}

public class Issue2172OldEditor : Editor
{

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)Issue7773.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue8186.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue2172.xaml.cs">
<DependentUpon>Issue2172.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)Issue3475.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue5749.xaml.cs">
<SubType>Code</SubType>
Expand Down Expand Up @@ -1763,4 +1767,10 @@
<Generator>MSBuild:Compile</Generator>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue2172.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</EmbeddedResource>
</ItemGroup>
</Project>
66 changes: 4 additions & 62 deletions Xamarin.Forms.Platform.UAP/EditorRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ namespace Xamarin.Forms.Platform.UWP
{
public class EditorRenderer : ViewRenderer<Editor, FormsTextBox>
{
private static FormsTextBox _copyOfTextBox;
static Windows.Foundation.Size _zeroSize = new Windows.Foundation.Size(0, 0);
bool _fontApplied;
Brush _backgroundColorFocusedDefaultBrush;
Brush _textDefaultBrush;
Expand Down Expand Up @@ -179,65 +177,6 @@ void OnNativeTextChanged(object sender, Windows.UI.Xaml.Controls.TextChangedEven
Element.SetValueCore(Editor.TextProperty, Control.Text);
}

/*
* Purely invalidating the layout as text is added to the TextBox will not cause it to expand.
* If the TextBox is set to WordWrap and it is part of the layout it will refuse to Measure itself beyond its established width.
* Even giving it infinite constraints will cause it to always set its DesiredSize to the same width but with a vertical growth.
* The only way I was able to grow it was by setting layout renderers width explicitly to some value but then it just set its own Width to that Width which is not helpful.
* Even vertically it would measure oddly in cases of rapid text changes.
* Holding down the backspace key or enter key would cause the final result to be not quite right.
* Both of these issues were fixed by just creating a static TextBox that is not part of the layout which let me just measure
* the size of the text as it would fit into the TextBox unconstrained and then just return that Size from the GetDesiredSize call.
* */
Size GetCopyOfSize(FormsTextBox control, Windows.Foundation.Size constraint)
{
if (_copyOfTextBox == null)
{
_copyOfTextBox = CreateTextBox();

// This causes the copy to be initially setup correctly.
// I found that if the first measure of this copy occurs with Text then it will just keep defaulting to a measure with no text.
_copyOfTextBox.Measure(_zeroSize);
}

_copyOfTextBox.Text = control.Text;
_copyOfTextBox.FontSize = control.FontSize;
_copyOfTextBox.FontFamily = control.FontFamily;
_copyOfTextBox.FontStretch = control.FontStretch;
_copyOfTextBox.FontStyle = control.FontStyle;
_copyOfTextBox.FontWeight = control.FontWeight;
_copyOfTextBox.Margin = control.Margin;
_copyOfTextBox.Padding = control.Padding;

// have to reset the measure to zero before it will re-measure itself
_copyOfTextBox.Measure(_zeroSize);
_copyOfTextBox.Measure(constraint);

Size result = new Size
(
Math.Ceiling(_copyOfTextBox.DesiredSize.Width),
Math.Ceiling(_copyOfTextBox.DesiredSize.Height)
);

return result;
}


SizeRequest CalculateDesiredSizes(FormsTextBox control, Windows.Foundation.Size constraint, EditorAutoSizeOption sizeOption)
{
if (sizeOption == EditorAutoSizeOption.TextChanges)
{
Size result = GetCopyOfSize(control, constraint);
control.Measure(constraint);
return new SizeRequest(result);
}
else
{
control.Measure(constraint);
Size result = new Size(Math.Ceiling(control.DesiredSize.Width), Math.Ceiling(control.DesiredSize.Height));
return new SizeRequest(result);
}
}

public override SizeRequest GetDesiredSize(double widthConstraint, double heightConstraint)
{
Expand All @@ -246,7 +185,10 @@ public override SizeRequest GetDesiredSize(double widthConstraint, double height
if (Children.Count == 0 || child == null)
return new SizeRequest();

return CalculateDesiredSizes(child, new Windows.Foundation.Size(widthConstraint, heightConstraint), Element.AutoSize);
var constraint = new Windows.Foundation.Size(widthConstraint, heightConstraint);
child.Measure(constraint);
var result = FormsTextBox.GetCopyOfSize(child, constraint);
return new SizeRequest(result);
}

void UpdateFont()
Expand Down
13 changes: 13 additions & 0 deletions Xamarin.Forms.Platform.UAP/EntryRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -457,5 +457,18 @@ void UpdateIsReadOnly()
{
Control.IsReadOnly = Element.IsReadOnly;
}

public override SizeRequest GetDesiredSize(double widthConstraint, double heightConstraint)
{
FormsTextBox child = Control;

if (Children.Count == 0 || child == null)
return new SizeRequest();

var constraint = new Windows.Foundation.Size(widthConstraint, heightConstraint);
child.Measure(constraint);
var result = FormsTextBox.GetCopyOfSize(child, constraint);
return new SizeRequest(result);
}
}
}
Loading