From 6f3a1db9a6dd11bfbea9652aae073db4afb77eb9 Mon Sep 17 00:00:00 2001 From: Benedikt Schroeder Date: Sun, 3 May 2020 21:49:00 +0200 Subject: [PATCH 1/2] Fix TextBox invalidation --- .../Presenters/TextPresenter.cs | 46 +++++++++---------- src/Avalonia.Visuals/Media/FormattedText.cs | 6 +++ src/Skia/Avalonia.Skia/FormattedTextImpl.cs | 12 ++++- 3 files changed, 39 insertions(+), 25 deletions(-) diff --git a/src/Avalonia.Controls/Presenters/TextPresenter.cs b/src/Avalonia.Controls/Presenters/TextPresenter.cs index 905a14cfee..2301c3037a 100644 --- a/src/Avalonia.Controls/Presenters/TextPresenter.cs +++ b/src/Avalonia.Controls/Presenters/TextPresenter.cs @@ -74,16 +74,15 @@ namespace Avalonia.Controls.Presenters static TextPresenter() { - AffectsRender(PasswordCharProperty, - SelectionBrushProperty, SelectionForegroundBrushProperty, - SelectionStartProperty, SelectionEndProperty); + AffectsRender(SelectionBrushProperty); - Observable.Merge( - TextProperty.Changed, - SelectionStartProperty.Changed, - SelectionEndProperty.Changed, - PasswordCharProperty.Changed - ).AddClassHandler((x,_) => x.InvalidateFormattedText()); + Observable.Merge(TextProperty.Changed, TextBlock.ForegroundProperty.Changed, + TextAlignmentProperty.Changed, TextWrappingProperty.Changed, + TextBlock.FontSizeProperty.Changed, TextBlock.FontStyleProperty.Changed, + TextBlock.FontWeightProperty.Changed, TextBlock.FontFamilyProperty.Changed, + SelectionStartProperty.Changed, SelectionEndProperty.Changed, + SelectionForegroundBrushProperty.Changed + ).AddClassHandler((x, _) => x.InvalidateFormattedText()); CaretIndexProperty.Changed.AddClassHandler((x, e) => x.CaretIndexChanged((int)e.NewValue)); } @@ -184,7 +183,7 @@ namespace Avalonia.Controls.Presenters { get { - return _formattedText ?? (_formattedText = CreateFormattedText(Bounds.Size, Text)); + return _formattedText ?? (_formattedText = CreateFormattedText()); } } @@ -219,7 +218,7 @@ namespace Avalonia.Controls.Presenters get => GetValue(SelectionForegroundBrushProperty); set => SetValue(SelectionForegroundBrushProperty, value); } - + public IBrush CaretBrush { get => GetValue(CaretBrushProperty); @@ -284,13 +283,9 @@ namespace Avalonia.Controls.Presenters /// protected void InvalidateFormattedText() { - if (_formattedText != null) - { - _constraint = _formattedText.Constraint; - _formattedText = null; - } + _formattedText = null; - InvalidateVisual(); + InvalidateMeasure(); } /// @@ -307,6 +302,7 @@ namespace Avalonia.Controls.Presenters } FormattedText.Constraint = Bounds.Size; + context.DrawText(Foreground, new Point(), FormattedText); } @@ -424,20 +420,20 @@ namespace Avalonia.Controls.Presenters /// /// Creates the used to render the text. /// - /// The constraint of the text. - /// The text to generated the for. /// A object. - protected virtual FormattedText CreateFormattedText(Size constraint, string text) + protected virtual FormattedText CreateFormattedText() { FormattedText result = null; + var text = Text; + if (PasswordChar != default(char)) { - result = CreateFormattedTextInternal(constraint, new string(PasswordChar, text?.Length ?? 0)); + result = CreateFormattedTextInternal(_constraint, new string(PasswordChar, text?.Length ?? 0)); } else { - result = CreateFormattedTextInternal(constraint, text); + result = CreateFormattedTextInternal(_constraint, text); } var selectionStart = SelectionStart; @@ -467,13 +463,15 @@ namespace Avalonia.Controls.Presenters { if (TextWrapping == TextWrapping.Wrap) { - FormattedText.Constraint = new Size(availableSize.Width, double.PositiveInfinity); + _constraint = new Size(availableSize.Width, double.PositiveInfinity); } else { - FormattedText.Constraint = Size.Infinity; + _constraint = Size.Infinity; } + _formattedText = null; + return FormattedText.Bounds.Size; } diff --git a/src/Avalonia.Visuals/Media/FormattedText.cs b/src/Avalonia.Visuals/Media/FormattedText.cs index 69806b22f2..53231ee1dd 100644 --- a/src/Avalonia.Visuals/Media/FormattedText.cs +++ b/src/Avalonia.Visuals/Media/FormattedText.cs @@ -200,7 +200,13 @@ namespace Avalonia.Media private void Set(ref T field, T value) { + if (field != null && field.Equals(value)) + { + return; + } + field = value; + _platformImpl = null; } } diff --git a/src/Skia/Avalonia.Skia/FormattedTextImpl.cs b/src/Skia/Avalonia.Skia/FormattedTextImpl.cs index 6022e7a552..5f876464e2 100644 --- a/src/Skia/Avalonia.Skia/FormattedTextImpl.cs +++ b/src/Skia/Avalonia.Skia/FormattedTextImpl.cs @@ -149,7 +149,17 @@ namespace Avalonia.Skia if (index >= Text.Length || index < 0) { var r = rects.LastOrDefault(); - return new Rect(r.X + r.Width, r.Y, 0, _lineHeight); + + var c = Text[Text.Length - 1]; + + switch (c) + { + case '\n': + case '\r': + return new Rect(r.X, r.Y, 0, _lineHeight); + default: + return new Rect(r.X + r.Width, r.Y, 0, _lineHeight); + } } return rects[index]; } From d5a317cee6dc0e5f038bba2ce9e9f6a4a4a455c3 Mon Sep 17 00:00:00 2001 From: Benedikt Schroeder Date: Mon, 4 May 2020 15:58:13 +0200 Subject: [PATCH 2/2] Invalidate TextBox on PasswordChar change --- src/Avalonia.Controls/Presenters/TextPresenter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/Presenters/TextPresenter.cs b/src/Avalonia.Controls/Presenters/TextPresenter.cs index 2301c3037a..9cbde72f7f 100644 --- a/src/Avalonia.Controls/Presenters/TextPresenter.cs +++ b/src/Avalonia.Controls/Presenters/TextPresenter.cs @@ -81,7 +81,7 @@ namespace Avalonia.Controls.Presenters TextBlock.FontSizeProperty.Changed, TextBlock.FontStyleProperty.Changed, TextBlock.FontWeightProperty.Changed, TextBlock.FontFamilyProperty.Changed, SelectionStartProperty.Changed, SelectionEndProperty.Changed, - SelectionForegroundBrushProperty.Changed + SelectionForegroundBrushProperty.Changed, PasswordCharProperty.Changed ).AddClassHandler((x, _) => x.InvalidateFormattedText()); CaretIndexProperty.Changed.AddClassHandler((x, e) => x.CaretIndexChanged((int)e.NewValue));