Skip to content

Commit

Permalink
Ensure that the z-index sort also preserves original add order (#7270)
Browse files Browse the repository at this point in the history
Fixes #7122
  • Loading branch information
hartez committed May 18, 2022
1 parent cb2014b commit efac4b0
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 7 deletions.
37 changes: 30 additions & 7 deletions src/Core/src/Handlers/Layout/LayoutExtensions.cs
Expand Up @@ -5,26 +5,49 @@ namespace Microsoft.Maui.Handlers
{
internal static class LayoutExtensions
{
class ZIndexComparer : IComparer<IView>
record ViewAndIndex(IView View, int Index);

class ZIndexComparer : IComparer<ViewAndIndex>
{
public int Compare(IView? x, IView? y)
public int Compare(ViewAndIndex? x, ViewAndIndex? y)
{
if (x == null || y == null)
if(x == null || y == null)
{
return 0;
}

return x.ZIndex.CompareTo(y.ZIndex);
var zIndexCompare = x.View.ZIndex.CompareTo(y.View.ZIndex);

if (zIndexCompare == 0)
{
return x.Index.CompareTo(y.Index);
}

return zIndexCompare;
}
}

static ZIndexComparer s_comparer = new();

public static IView[] OrderByZIndex(this ILayout layout)
{
var ordered = new IView[layout.Count];
layout.CopyTo(ordered, 0);
Array.Sort(ordered, s_comparer);
var count = layout.Count;
var indexedViews = new ViewAndIndex[count];

for (int n = 0; n < count; n++)
{
indexedViews[n] = new ViewAndIndex(layout[n], n);
}

Array.Sort(indexedViews, s_comparer);

var ordered = new IView[count];

for (int n = 0; n < count; n++)
{
ordered[n] = indexedViews[n].View;
}

return ordered;
}

Expand Down
32 changes: 32 additions & 0 deletions src/Core/tests/UnitTests/Layouts/ZIndexTests.cs
Expand Up @@ -243,5 +243,37 @@ public void ZIndexUpdatePreservesAddOrderForEqualZIndexes()
Assert.Equal(view2, zordered[2]);
Assert.Equal(view3, zordered[3]);
}

[Fact]
public void ZIndexUpdatePreservesAddOrderLotsOfEqualZIndexes()
{
// This tests the same thing as ZIndexUpdatePreservesAddOrderForEqualZIndexes,
// but for more views - since the sorting algorithm can change when the arrays
// are larger, we were running into situations where layouts with more controls
// were _not_ preserving the Add() order when sorting by z-index.

var layout = new FakeLayout();

int views = 100;
int iterations = 10;

var toAdd = new IView[views];

for (int n = 0; n < views; n++)
{
toAdd[n] = CreateTestView(zIndex: 0);
layout.Add(toAdd[n]);
}

for (int i = 0; i < iterations; i++)
{
var zordered = layout.OrderByZIndex();

for (int n = 0; n < zordered.Length; n++)
{
Assert.Equal(toAdd[n], zordered[n]);
}
}
}
}
}

0 comments on commit efac4b0

Please sign in to comment.