Browse Source

Fix InlinesCollection Logical/VisualParent update (#14679)

* Add failing test

* Update Visual/LogicalTree when parents change
x11_allowed_actions
Benedikt Stebner 3 years ago
committed by GitHub
parent
commit
599cf1f297
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 90
      src/Avalonia.Controls/Documents/InlineCollection.cs
  2. 19
      tests/Avalonia.Controls.UnitTests/TextBlockTests.cs

90
src/Avalonia.Controls/Documents/InlineCollection.cs

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using Avalonia.Collections; using Avalonia.Collections;
using Avalonia.LogicalTree; using Avalonia.LogicalTree;
using Avalonia.Metadata; using Avalonia.Metadata;
@ -23,32 +24,8 @@ namespace Avalonia.Controls.Documents
ResetBehavior = ResetBehavior.Remove; ResetBehavior = ResetBehavior.Remove;
this.ForEachItem( this.ForEachItem(
x => OnAdd,
{ OnRemove,
x.InlineHost = InlineHost;
LogicalChildren?.Add(x);
if (x is InlineUIContainer container)
{
InlineHost?.VisualChildren.Add(container.Child);
}
Invalidate();
},
x =>
{
LogicalChildren?.Remove(x);
if(x is InlineUIContainer container)
{
InlineHost?.VisualChildren.Remove(container.Child);
}
x.InlineHost = null;
Invalidate();
},
() => throw new NotSupportedException()); () => throw new NotSupportedException());
} }
@ -70,9 +47,11 @@ namespace Avalonia.Controls.Documents
get => _inlineHost; get => _inlineHost;
set set
{ {
var oldValue = _inlineHost;
_inlineHost = value; _inlineHost = value;
OnInlineHostChanged(value); OnInlineHostChanged(oldValue, value);
} }
} }
@ -118,7 +97,7 @@ namespace Avalonia.Controls.Documents
/// <summary> /// <summary>
/// Adds a text segment to the collection. /// Adds a text segment to the collection.
/// <remarks> /// <remarks>
/// For non complex content this appends the text to the end of currently held text. /// For non-complex content this appends the text to the end of currently held text.
/// For complex content this adds a <see cref="Run"/> to the collection. /// For complex content this adds a <see cref="Run"/> to the collection.
/// </remarks> /// </remarks>
/// </summary> /// </summary>
@ -159,25 +138,66 @@ namespace Avalonia.Controls.Documents
Invalidated?.Invoke(this, EventArgs.Empty); Invalidated?.Invoke(this, EventArgs.Empty);
} }
private void OnParentChanged(IAvaloniaList<ILogical>? oldParent, IAvaloniaList<ILogical>? newParent) private void OnParentChanged(ICollection<ILogical>? oldValue, ICollection<ILogical>? newValue)
{ {
foreach (var child in this) foreach (var child in this)
{ {
if (oldParent != newParent) if (Equals(oldValue, newValue))
{ {
oldParent?.Remove(child); continue;
newParent?.Add(child);
} }
oldValue?.Remove(child);
newValue?.Add(child);
} }
Invalidate();
} }
private void OnInlineHostChanged(IInlineHost? inlineHost) private void OnInlineHostChanged(IInlineHost? oldValue, IInlineHost? newValue)
{ {
foreach (var child in this) foreach (var child in this)
{ {
child.InlineHost = inlineHost; if (child is not InlineUIContainer container)
{
continue;
}
oldValue?.VisualChildren.Remove(container.Child);
newValue?.VisualChildren.Add(container.Child);
}
Invalidate();
}
private void OnAdd(TextElement inline)
{
inline.InlineHost = InlineHost;
LogicalChildren?.Add(inline);
if (inline is InlineUIContainer container)
{
InlineHost?.VisualChildren.Add(container.Child);
} }
Invalidate();
}
private void OnRemove(TextElement inline)
{
LogicalChildren?.Remove(inline);
if (inline is InlineUIContainer container)
{
InlineHost?.VisualChildren.Remove(container.Child);
}
inline.InlineHost = null;
Invalidate();
} }
} }
} }

19
tests/Avalonia.Controls.UnitTests/TextBlockTests.cs

@ -51,6 +51,25 @@ namespace Avalonia.Controls.UnitTests
} }
} }
[Fact]
public void Changing_Inlines_Should_Attach_Embedded_Controls_To_Parents()
{
using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
{
var target = new TextBlock();
var control = new Border();
var inlineUIContainer = new InlineUIContainer { Child = control };
target.Inlines = new InlineCollection { inlineUIContainer };
Assert.Equal(inlineUIContainer, control.Parent);
Assert.Equal(target, control.VisualParent);
}
}
[Fact] [Fact]
public void Can_Call_Measure_Without_InvalidateTextLayout() public void Can_Call_Measure_Without_InvalidateTextLayout()
{ {

Loading…
Cancel
Save