Browse Source

Merge pull request #12589 from Actipro/fix-textbox-padding

Fixes TextBox measure logic for MaxLines scenario
release/11.0.4
Dan Walmsley 3 years ago
committed by GitHub
parent
commit
283c3cdfeb
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 34
      src/Avalonia.Controls/TextBox.cs
  2. 79
      tests/Avalonia.Controls.UnitTests/TextBoxTests.cs

34
src/Avalonia.Controls/TextBox.cs

@ -1879,6 +1879,37 @@ namespace Avalonia.Controls
return text.Substring(start, end - start);
}
/// <summary>
/// Returns the sum of any vertical whitespace added between the <see cref="ScrollViewer"/> and <see cref="TextPresenter"/> in the control template.
/// </summary>
/// <returns>The total vertical whitespace.</returns>
private double GetVerticalSpaceBetweenScrollViewerAndPresenter()
{
var verticalSpace = 0.0;
if (_presenter != null)
{
Visual? visual = _presenter;
while ((visual != null) && (visual != this))
{
if (visual == _scrollViewer)
{
// ScrollViewer is a stopping point and should only include the Padding
verticalSpace += _scrollViewer.Padding.Top + _scrollViewer.Padding.Bottom;
break;
}
var margin = visual.GetValue<Thickness>(Layoutable.MarginProperty);
var padding = visual.GetValue<Thickness>(Decorator.PaddingProperty);
verticalSpace += margin.Top + padding.Top + padding.Bottom + margin.Bottom;
visual = visual.VisualParent;
}
}
return verticalSpace;
}
/// <summary>
/// Raises both the <see cref="TextChanging"/> and <see cref="TextChanged"/> events.
/// </summary>
@ -2032,8 +2063,9 @@ namespace Avalonia.Controls
var typeface = new Typeface(FontFamily, FontStyle, FontWeight, FontStretch);
var paragraphProperties = TextLayout.CreateTextParagraphProperties(typeface, fontSize, null, default, default, null, default, LineHeight, default);
var textLayout = new TextLayout(new MaxLinesTextSource(MaxLines), paragraphProperties);
var verticalSpace = GetVerticalSpaceBetweenScrollViewerAndPresenter();
maxHeight = Math.Ceiling(textLayout.Height);
maxHeight = Math.Ceiling(textLayout.Height + verticalSpace);
}
_scrollViewer.SetCurrentValue(MaxHeightProperty, maxHeight);

79
tests/Avalonia.Controls.UnitTests/TextBoxTests.cs

@ -15,6 +15,7 @@ using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Rendering.Composition;
using Avalonia.UnitTests;
using Avalonia.VisualTree;
using Moq;
using Xunit;
@ -916,6 +917,82 @@ namespace Avalonia.Controls.UnitTests
}
}
[Theory]
[InlineData(1)]
[InlineData(2)]
[InlineData(3)]
public void MaxLines_Sets_ScrollViewer_MaxHeight(int maxLines)
{
using (UnitTestApplication.Start(Services))
{
var target = new TextBox
{
Template = CreateTemplate(),
MaxLines = maxLines,
// Define explicit whole number line height for predictable calculations
LineHeight = 20
};
var impl = CreateMockTopLevelImpl();
var topLevel = new TestTopLevel(impl.Object)
{
Template = CreateTopLevelTemplate(),
Content = target
};
topLevel.ApplyTemplate();
topLevel.LayoutManager.ExecuteInitialLayoutPass();
var textPresenter = target.FindDescendantOfType<TextPresenter>();
Assert.Equal("PART_TextPresenter", textPresenter.Name);
Assert.Equal(new Thickness(0), textPresenter.Margin); // Test assumes no margin on TextPresenter
var scrollViewer = target.FindDescendantOfType<ScrollViewer>();
Assert.Equal("PART_ScrollViewer", scrollViewer.Name);
Assert.Equal(maxLines * target.LineHeight, scrollViewer.MaxHeight);
}
}
[Theory]
[InlineData(1)]
[InlineData(2)]
[InlineData(3)]
public void MaxLines_Sets_ScrollViewer_MaxHeight_With_TextPresenter_Margin(int maxLines)
{
using (UnitTestApplication.Start(Services))
{
var target = new TextBox
{
Template = CreateTemplate(),
MaxLines = maxLines,
// Define explicit whole number line height for predictable calculations
LineHeight = 20
};
var impl = CreateMockTopLevelImpl();
var topLevel = new TestTopLevel(impl.Object)
{
Template = CreateTopLevelTemplate(),
Content = target
};
topLevel.ApplyTemplate();
topLevel.LayoutManager.ExecuteInitialLayoutPass();
var textPresenter = target.FindDescendantOfType<TextPresenter>();
Assert.Equal("PART_TextPresenter", textPresenter.Name);
var textPresenterMargin = new Thickness(horizontal: 0, vertical: 3);
textPresenter.Margin = textPresenterMargin;
target.InvalidateMeasure();
target.Measure(Size.Infinity);
var scrollViewer = target.FindDescendantOfType<ScrollViewer>();
Assert.Equal("PART_ScrollViewer", scrollViewer.Name);
Assert.Equal((maxLines * target.LineHeight) + textPresenterMargin.Top + textPresenterMargin.Bottom, scrollViewer.MaxHeight);
}
}
[Fact]
public void CanUndo_CanRedo_Is_False_When_Initialized()
{
@ -1125,7 +1202,7 @@ namespace Avalonia.Controls.UnitTests
return new FuncControlTemplate<TextBox>((control, scope) =>
new ScrollViewer
{
Name = "Part_ScrollViewer",
Name = "PART_ScrollViewer",
Template = new FuncControlTemplate<ScrollViewer>(ScrollViewerTests.CreateTemplate),
Content = new TextPresenter
{

Loading…
Cancel
Save