Skip to content

Commit

Permalink
IContainer as IList<IView> (#1724)
Browse files Browse the repository at this point in the history
* IContainer proposal

* Update the test classes to match the updated interfaces

* Make substitution work for new layout interface

* Fix Windows

* Implement methods on stub I missed

* And another thing I forgot to implement

* Remove commented code

* Make IContainer implementation explicit

* Fix child collection access in test
  • Loading branch information
hartez committed Jul 22, 2021
1 parent 870d784 commit f0e8ea7
Show file tree
Hide file tree
Showing 23 changed files with 254 additions and 207 deletions.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

76 changes: 76 additions & 0 deletions src/Controls/src/Core/HandlerImpl/Layout.Impl.cs
@@ -0,0 +1,76 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

namespace Microsoft.Maui.Controls
{
public abstract partial class Layout<T>
{
int ICollection<IView>.Count => _children.Count;
bool ICollection<IView>.IsReadOnly => ((ICollection<IView>) _children).IsReadOnly;
public IView this[int index] { get => _children[index]; set => _children[index] = (T)value; }

void ICollection<IView>.Add(IView child)
{
if (child is T view)
{
_children.Add(view);
}
}

bool ICollection<IView>.Remove(IView child)
{
if (child is T view)
{
_children.Remove(view);
return true;
}

return false;
}

int IList<IView>.IndexOf(IView child)
{
return _children.IndexOf(child);
}

void IList<IView>.Insert(int index, IView child)
{
if (child is T view)
{
_children.Insert(index, view);
}
}

void IList<IView>.RemoveAt(int index)
{
_children.RemoveAt(index);
}

void ICollection<IView>.Clear()
{
_children.Clear();
}

bool ICollection<IView>.Contains(IView child)
{
return _children.Contains(child);
}

void ICollection<IView>.CopyTo(IView[] array, int arrayIndex)
{
_children.CopyTo(array, arrayIndex);
}

IEnumerator<IView> IEnumerable<IView>.GetEnumerator()
{
return _children.GetEnumerator();
}

IEnumerator IEnumerable.GetEnumerator()
{
return _children.GetEnumerator();
}
}
}
26 changes: 3 additions & 23 deletions src/Controls/src/Core/Layout.cs
@@ -1,4 +1,5 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
Expand All @@ -10,11 +11,8 @@
namespace Microsoft.Maui.Controls
{
[ContentProperty(nameof(Children))]
public abstract class Layout<T> : Layout, Microsoft.Maui.ILayout, IViewContainer<T> where T : View
public abstract partial class Layout<T> : Layout, Microsoft.Maui.ILayout, IViewContainer<T> where T : View
{
// TODO ezhart We should look for a way to optimize this a bit
IReadOnlyList<Microsoft.Maui.IView> Microsoft.Maui.IContainer.Children => Children.ToList();

readonly ElementCollection<T> _children;

protected Layout() => _children = new ElementCollection<T>(InternalChildren);
Expand Down Expand Up @@ -46,28 +44,10 @@ protected virtual void OnAdded(T view)
protected virtual void OnRemoved(T view)
{
}

public void Add(IView child)
{
if (child is T view)
{
Children.Add(view);
}
}

public void Remove(IView child)
{
if (child is T view)
{
Children.Remove(view);
}
}
}

public abstract class Layout : View, ILayout, ILayoutController, IPaddingElement, IFrameworkElement, Microsoft.Maui.IContainer
public abstract class Layout : View, ILayout, ILayoutController, IPaddingElement, IFrameworkElement
{
IReadOnlyList<Microsoft.Maui.IView> Microsoft.Maui.IContainer.Children => InternalChildren.OfType<IView>().ToList();

public static readonly BindableProperty IsClippedToBoundsProperty =
BindableProperty.Create(nameof(IsClippedToBounds), typeof(bool), typeof(Layout), false);

Expand Down
4 changes: 2 additions & 2 deletions src/Controls/src/Core/Layout/GridLayout.cs
Expand Up @@ -231,10 +231,10 @@ public override void Add(IView child)
}
}

public override void Remove(IView child)
public override bool Remove(IView child)
{
_viewInfo.Remove(child);
base.Remove(child);
return base.Remove(child);
}

protected override ILayoutManager CreateLayoutManager() => new GridLayoutManager(this);
Expand Down
44 changes: 7 additions & 37 deletions src/Controls/src/Core/Layout/Layout.cs
Expand Up @@ -25,11 +25,8 @@ public abstract class Layout : View, Microsoft.Maui.ILayout, IList<IView>, IPadd

public bool IsReadOnly => ((ICollection<IView>)_children).IsReadOnly;

IReadOnlyList<IView> IContainer.Children => _children.AsReadOnly();

public IView this[int index] { get => _children[index]; set => _children[index] = value; }


public Thickness Padding
{
get => (Thickness)GetValue(PaddingElement.PaddingProperty);
Expand All @@ -53,56 +50,44 @@ public override SizeRequest GetSizeRequest(double widthConstraint, double height
protected override Size MeasureOverride(double widthConstraint, double heightConstraint)
{
var margin = (this as IView)?.Margin ?? Thickness.Zero;

// Adjust the constraints to account for the margins
widthConstraint -= margin.HorizontalThickness;
heightConstraint -= margin.VerticalThickness;

var sizeWithoutMargins = LayoutManager.Measure(widthConstraint, heightConstraint);
DesiredSize = new Size(sizeWithoutMargins.Width + Margin.HorizontalThickness,
sizeWithoutMargins.Height + Margin.VerticalThickness);

return DesiredSize;
}

protected override Size ArrangeOverride(Rectangle bounds)
{
base.ArrangeOverride(bounds);

Frame = bounds;

LayoutManager.ArrangeChildren(Frame);

foreach (var child in Children)
{
child.Handler?.NativeArrange(child.Frame);
}

return Frame.Size;
}

protected override void InvalidateMeasureOverride()
{
base.InvalidateMeasureOverride();

foreach (var child in Children)
{
child.InvalidateMeasure();
}
}

public virtual void Add(IView child)
{
if (child == null)
return;

_children.Add(child);

if (child is Element element)
element.Parent = this;

InvalidateMeasure();

LayoutHandler?.Add(child);
}

Expand Down Expand Up @@ -144,19 +129,21 @@ public void Insert(int index, IView child)
LayoutHandler?.Add(child);
}

public virtual void Remove(IView child)
public virtual bool Remove(IView child)
{
if (child == null)
return;
return false;

_children.Remove(child);
var result = _children.Remove(child);

if (child is Element element)
element.Parent = null;

InvalidateMeasure();

LayoutHandler?.Remove(child);

return result;
}

public void RemoveAt(int index)
Expand All @@ -178,23 +165,6 @@ public void RemoveAt(int index)
LayoutHandler?.Remove(child);
}

bool ICollection<IView>.Remove(IView child)
{
if (child == null)
return false;

var result = _children.Remove(child);

if (child is Element element)
element.Parent = null;

InvalidateMeasure();

LayoutHandler?.Remove(child);

return result;
}

void IPaddingElement.OnPaddingPropertyChanged(Thickness oldValue, Thickness newValue)
{
InvalidateMeasure();
Expand Down
Expand Up @@ -97,7 +97,7 @@ public void GridInsideStackLayout()
view.GetDesiredSize(default, default).ReturnsForAnyArgs(expectedSize);
label.Handler = view;

stackLayout.Add(grid);
stackLayout.Children.Add(grid);
grid.Children.Add(label);
contentPage.Content = stackLayout;

Expand Down
7 changes: 2 additions & 5 deletions src/Core/src/Core/IContainer.cs
Expand Up @@ -5,11 +5,8 @@ namespace Microsoft.Maui
/// <summary>
/// Provides functionality to act as containers for views.
/// </summary>
public interface IContainer
public interface IContainer : IList<IView>
{
/// <summary>
/// Gets the collection of children that the Container contains.
/// </summary>
IReadOnlyList<IView> Children { get; }

}
}
12 changes: 0 additions & 12 deletions src/Core/src/Core/ILayout.cs
Expand Up @@ -13,18 +13,6 @@ public interface ILayout : IView, IContainer
/// </summary>
ILayoutHandler LayoutHandler { get; }

/// <summary>
/// Add a child View to the Layout.
/// </summary>
/// <param name="child">The child View to add to the Layout.</param>
void Add(IView child);

/// <summary>
/// Remove a child View from the Layout.
/// </summary>
/// <param name="child">The child View to remove from the Layout.</param>
void Remove(IView child);

/// <summary>
/// The space between the outer edge of the ILayout's content area and its children.
/// </summary>
Expand Down
2 changes: 1 addition & 1 deletion src/Core/src/Handlers/Layout/LayoutHandler.Android.cs
Expand Up @@ -33,7 +33,7 @@ public override void SetVirtualView(IView view)
NativeView.CrossPlatformArrange = VirtualView.Arrange;

NativeView.RemoveAllViews();
foreach (var child in VirtualView.Children)
foreach (var child in VirtualView)
{
NativeView.AddView(child.ToNative(MauiContext));
}
Expand Down
2 changes: 1 addition & 1 deletion src/Core/src/Handlers/Layout/LayoutHandler.Windows.cs
Expand Up @@ -26,7 +26,7 @@ public override void SetVirtualView(IView view)
NativeView.CrossPlatformArrange = VirtualView.Arrange;

NativeView.Children.Clear();
foreach (var child in VirtualView.Children)
foreach (var child in VirtualView)
{
Add(child);
}
Expand Down
2 changes: 1 addition & 1 deletion src/Core/src/Handlers/Layout/LayoutHandler.iOS.cs
Expand Up @@ -40,7 +40,7 @@ public override void SetVirtualView(IView view)
child.RemoveFromSuperview();
}

foreach (var child in VirtualView.Children)
foreach (var child in VirtualView)
{
NativeView.AddSubview(child.ToNative(MauiContext));
}
Expand Down
2 changes: 1 addition & 1 deletion src/Core/src/HotReload/HotReloadExtensions.cs
Expand Up @@ -29,7 +29,7 @@ public static void CheckHandlers(this IView view)

if (view is IContainer layout)
{
foreach (var v in layout.Children)
foreach (var v in layout)
CheckHandlers(v);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/Core/src/Layouts/FlexLayoutManager.cs
Expand Up @@ -17,7 +17,7 @@ public void ArrangeChildren(Rectangle childBounds)
{
FlexLayout.Layout(childBounds.Width, childBounds.Height);

foreach (var child in FlexLayout.Children)
foreach (var child in FlexLayout)
{
var frame = FlexLayout.GetFlexFrame(child);
if (double.IsNaN(frame.X)
Expand Down

0 comments on commit f0e8ea7

Please sign in to comment.