diff --git a/samples/Sandbox/MainWindow.axaml b/samples/Sandbox/MainWindow.axaml index 0fc78795a6..cf2ce63c1f 100644 --- a/samples/Sandbox/MainWindow.axaml +++ b/samples/Sandbox/MainWindow.axaml @@ -9,6 +9,21 @@ + + + + + + diff --git a/samples/Sandbox/MainWindow.axaml.cs b/samples/Sandbox/MainWindow.axaml.cs index 7a8b56bbb6..3040385708 100644 --- a/samples/Sandbox/MainWindow.axaml.cs +++ b/samples/Sandbox/MainWindow.axaml.cs @@ -3,7 +3,9 @@ using System.Diagnostics; using System.Runtime.CompilerServices; using Avalonia; using Avalonia.Controls; +using Avalonia.Controls.Documents; using Avalonia.Controls.Presenters; +using Avalonia.Interactivity; using Avalonia.Markup.Xaml; using Avalonia.VisualTree; @@ -11,6 +13,8 @@ namespace Sandbox { public class MainWindow : Window { + private TestViewModel _dc; + public MainWindow() { this.InitializeComponent(); @@ -27,13 +31,30 @@ namespace Sandbox var textPresenter = e.NameScope.Find("PART_TextPresenter") as TextPresenter; - DataContext = new TestViewModel(textPresenter); + _dc = new TestViewModel(textPresenter); + + DataContext = _dc; } private void InitializeComponent() { AvaloniaXamlLoader.Load(this); } + + private void Button_OnClick(object? sender, RoutedEventArgs e) + { + _dc.InlineCollection = new InlineCollection + { + new Run(""), + new Run("test3") {FontWeight = Avalonia.Media.FontWeight.Bold}, + }; + // _dc.Text = "nununu"; + } + + private void TextButton_OnClick(object? sender, RoutedEventArgs e) + { + _dc.Text = "nununu"; + } } public class TestViewModel : ViewModelBase @@ -46,6 +67,29 @@ namespace Sandbox _textPresenter = textPresenter; } + private InlineCollection _inlineCollection; + private string _text; + + public string Text + { + get => _text; + set + { + _text = value; + RaisePropertyChanged(); + } + } + + public InlineCollection InlineCollection + { + get => _inlineCollection; + set + { + _inlineCollection = value; + RaisePropertyChanged(); + } + } + public double Distance { get => _distance; diff --git a/src/Avalonia.Base/Media/TextFormatting/TextLayout.cs b/src/Avalonia.Base/Media/TextFormatting/TextLayout.cs index f3e8b5969c..0828b6518a 100644 --- a/src/Avalonia.Base/Media/TextFormatting/TextLayout.cs +++ b/src/Avalonia.Base/Media/TextFormatting/TextLayout.cs @@ -537,8 +537,13 @@ namespace Avalonia.Media.TextFormatting /// /// The collapsing width. /// The . - private TextCollapsingProperties GetCollapsingProperties(double width) + private TextCollapsingProperties? GetCollapsingProperties(double width) { + if(_textTrimming == TextTrimming.None) + { + return null; + } + return _textTrimming.CreateCollapsingProperties(new TextCollapsingCreateInfo(width, _paragraphProperties.DefaultTextRunProperties)); } } diff --git a/src/Avalonia.Base/Media/TextFormatting/TextLine.cs b/src/Avalonia.Base/Media/TextFormatting/TextLine.cs index c8a23097db..61b24dc8c5 100644 --- a/src/Avalonia.Base/Media/TextFormatting/TextLine.cs +++ b/src/Avalonia.Base/Media/TextFormatting/TextLine.cs @@ -153,7 +153,7 @@ namespace Avalonia.Media.TextFormatting /// /// A value that represents a collapsed line that can be displayed. /// - public abstract TextLine Collapse(params TextCollapsingProperties[] collapsingPropertiesList); + public abstract TextLine Collapse(params TextCollapsingProperties?[] collapsingPropertiesList); /// /// Create a justified line based on justification text properties. diff --git a/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs b/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs index 0ee791d935..a0aae76fad 100644 --- a/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs +++ b/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs @@ -119,7 +119,7 @@ namespace Avalonia.Media.TextFormatting } /// - public override TextLine Collapse(params TextCollapsingProperties[] collapsingPropertiesList) + public override TextLine Collapse(params TextCollapsingProperties?[] collapsingPropertiesList) { if (collapsingPropertiesList.Length == 0) { @@ -128,6 +128,11 @@ namespace Avalonia.Media.TextFormatting var collapsingProperties = collapsingPropertiesList[0]; + if(collapsingProperties is null) + { + return this; + } + var collapsedRuns = collapsingProperties.Collapse(this); if (collapsedRuns is null) diff --git a/src/Avalonia.Controls/RichTextBlock.cs b/src/Avalonia.Controls/RichTextBlock.cs index 0c8b1d125d..2f8bed3be7 100644 --- a/src/Avalonia.Controls/RichTextBlock.cs +++ b/src/Avalonia.Controls/RichTextBlock.cs @@ -44,8 +44,8 @@ namespace Avalonia.Controls /// /// Defines the property. /// - public static readonly StyledProperty InlinesProperty = - AvaloniaProperty.Register( + public static readonly StyledProperty InlinesProperty = + AvaloniaProperty.Register( nameof(Inlines)); public static readonly DirectProperty CanCopyProperty = @@ -138,7 +138,7 @@ namespace Avalonia.Controls /// Gets or sets the inlines. /// [Content] - public InlineCollection Inlines + public InlineCollection? Inlines { get => GetValue(InlinesProperty); set => SetValue(InlinesProperty, value); @@ -159,7 +159,7 @@ namespace Avalonia.Controls remove => RemoveHandler(CopyingToClipboardEvent, value); } - internal bool HasComplexContent => Inlines.Count > 0; + internal bool HasComplexContent => Inlines != null && Inlines.Count > 0; /// /// Copies the current selection to the Clipboard. @@ -260,18 +260,18 @@ namespace Avalonia.Controls { if (!string.IsNullOrEmpty(_text)) { - Inlines.Add(_text); + Inlines?.Add(_text); _text = null; } - Inlines.Add(text); + Inlines?.Add(text); } } protected override string? GetText() { - return _text ?? Inlines.Text; + return _text ?? Inlines?.Text; } protected override void SetText(string? text) @@ -301,10 +301,10 @@ namespace Avalonia.Controls ITextSource textSource; - var inlines = Inlines; - if (HasComplexContent) { + var inlines = Inlines!; + var textRuns = new List(); foreach (var inline in inlines) @@ -537,7 +537,7 @@ namespace Avalonia.Controls switch (change.Property.Name) { - case nameof(InlinesProperty): + case nameof(Inlines): { OnInlinesChanged(change.OldValue as InlineCollection, change.NewValue as InlineCollection); InvalidateTextLayout(); @@ -553,7 +553,7 @@ namespace Avalonia.Controls return ""; } - var text = Inlines.Text ?? Text; + var text = GetText(); if (string.IsNullOrEmpty(text)) { diff --git a/tests/Avalonia.Controls.UnitTests/RichTextBlockTests.cs b/tests/Avalonia.Controls.UnitTests/RichTextBlockTests.cs index eb4b88956d..c74f13b808 100644 --- a/tests/Avalonia.Controls.UnitTests/RichTextBlockTests.cs +++ b/tests/Avalonia.Controls.UnitTests/RichTextBlockTests.cs @@ -48,5 +48,49 @@ namespace Avalonia.Controls.UnitTests Assert.False(target.IsMeasureValid); } } + + [Fact] + public void Changing_Inlines_Should_Invalidate_Measure() + { + using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface)) + { + var target = new RichTextBlock(); + + var inlines = new InlineCollection { new Run("Hello") }; + + target.Measure(Size.Infinity); + + Assert.True(target.IsMeasureValid); + + target.Inlines = inlines; + + Assert.False(target.IsMeasureValid); + } + } + + [Fact] + public void Changing_Inlines_Should_Reset_Inlines_Parent() + { + using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface)) + { + var target = new RichTextBlock(); + + var run = new Run("Hello"); + + target.Inlines.Add(run); + + target.Measure(Size.Infinity); + + Assert.True(target.IsMeasureValid); + + target.Inlines = null; + + Assert.Null(run.Parent); + + target.Inlines = new InlineCollection { run }; + + Assert.Equal(target, run.Parent); + } + } } } diff --git a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLayoutTests.cs b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLayoutTests.cs index 6d057d900e..c457a96299 100644 --- a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLayoutTests.cs +++ b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLayoutTests.cs @@ -993,9 +993,11 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting var currentX = 0.0; - for (int j = 0; j < clusters.Count; j++) - { - var cluster = clusters[j]; + var cluster = text.Length; + + for (int j = 0; j < clusters.Count - 1; j++) + { + var glyphAdvance = glyphAdvances[j]; var characterHit = textLine.GetCharacterHitFromDistance(currentX); @@ -1005,9 +1007,9 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting Assert.Equal(currentX, distance); - var glyphAdvance = glyphAdvances[j]; - currentX += glyphAdvance; + + cluster = clusters[j]; } } }