Browse Source

Fix InlinesCollection Logical/VisualParent update (#14679)

* Add failing test

* Update Visual/LogicalTree when parents change
x11_allowed_actions
Benedikt Stebner 2 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.Collections.Generic;
using Avalonia.Collections;
using Avalonia.LogicalTree;
using Avalonia.Metadata;
@ -23,32 +24,8 @@ namespace Avalonia.Controls.Documents
ResetBehavior = ResetBehavior.Remove;
this.ForEachItem(
x =>
{
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();
},
OnAdd,
OnRemove,
() => throw new NotSupportedException());
}
@ -70,9 +47,11 @@ namespace Avalonia.Controls.Documents
get => _inlineHost;
set
{
var oldValue = _inlineHost;
_inlineHost = value;
OnInlineHostChanged(value);
OnInlineHostChanged(oldValue, value);
}
}
@ -118,7 +97,7 @@ namespace Avalonia.Controls.Documents
/// <summary>
/// Adds a text segment to the collection.
/// <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.
/// </remarks>
/// </summary>
@ -159,25 +138,66 @@ namespace Avalonia.Controls.Documents
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)
{
if (oldParent != newParent)
if (Equals(oldValue, newValue))
{
oldParent?.Remove(child);
newParent?.Add(child);
continue;
}
oldValue?.Remove(child);
newValue?.Add(child);
}
Invalidate();
}
private void OnInlineHostChanged(IInlineHost? inlineHost)
private void OnInlineHostChanged(IInlineHost? oldValue, IInlineHost? newValue)
{
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]
public void Can_Call_Measure_Without_InvalidateTextLayout()
{

Loading…
Cancel
Save