* [C] index on VTChanges

    [C] send index on VTChange.Add
    [C] register LV cells as LogicalChildren
    [C] add index in VTChanges.Remove

    - fixes #11334
    - fixes #11335
    - fixes AB#1152749
    - fixes AB#1152814

* Update Xamarin.Forms.Core/Element.cs

change obsolescence message

Co-authored-by: Samantha Houts <samhouts@users.noreply.github.com>

Co-authored-by: Samantha Houts <samhouts@users.noreply.github.com>
This commit is contained in:
Stephane Delcroix 2020-09-02 11:08:18 +02:00 коммит произвёл GitHub
Родитель 16b290ae8d
Коммит 975577e837
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
21 изменённых файлов: 369 добавлений и 251 удалений

Просмотреть файл

@ -76,10 +76,13 @@ namespace Xamarin.Forms
child.PropertyChanged += ChildOnPropertyChanged;
}
protected override void OnChildRemoved(Element child)
[Obsolete("OnChildRemoved(Element) is obsolete as of version 4.8.0. Please use OnChildRemoved(Element, int) instead.")]
protected override void OnChildRemoved(Element child) => OnChildRemoved(child, -1);
protected override void OnChildRemoved(Element child, int oldLogicalIndex)
{
child.PropertyChanged -= ChildOnPropertyChanged;
base.OnChildRemoved(child);
base.OnChildRemoved(child, oldLogicalIndex);
}
[Obsolete("OnSizeRequest is obsolete as of version 2.2.0. Please use OnMeasure instead.")]

Просмотреть файл

@ -22,7 +22,7 @@ namespace Xamarin.Forms
if (_view != null)
{
OnChildRemoved(_view);
OnChildRemoved(_view, 0);
_view.ComputedConstraint = LayoutConstraint.None;
}

Просмотреть файл

@ -201,8 +201,6 @@ namespace Xamarin.Forms
SetInheritedBindingContext(this, null);
}
VisualDiagnostics.SendVisualTreeChanged(value, this);
OnParentSet();
OnPropertyChanged();
@ -325,17 +323,24 @@ namespace Xamarin.Forms
ChildAdded?.Invoke(this, new ElementEventArgs(child));
VisualDiagnostics.OnChildAdded(this, child);
OnDescendantAdded(child);
foreach (Element element in child.Descendants())
OnDescendantAdded(element);
}
protected virtual void OnChildRemoved(Element child)
[Obsolete("OnChildRemoved(Element) is obsolete as of version 4.8.0. Please use OnChildRemoved(Element, int) instead.")]
protected virtual void OnChildRemoved(Element child) => OnChildRemoved(child, -1);
protected virtual void OnChildRemoved(Element child, int oldLogicalIndex)
{
child.Parent = null;
ChildRemoved?.Invoke(child, new ElementEventArgs(child));
VisualDiagnostics.OnChildRemoved(this, child, oldLogicalIndex);
OnDescendantRemoved(child);
foreach (Element element in child.Descendants())
OnDescendantRemoved(element);

Просмотреть файл

@ -4,13 +4,7 @@ namespace Xamarin.Forms
{
public class ElementEventArgs : EventArgs
{
public ElementEventArgs(Element element)
{
if (element == null)
throw new ArgumentNullException("element");
Element = element;
}
public ElementEventArgs(Element element) => Element = element ?? throw new ArgumentNullException(nameof(element));
public Element Element { get; private set; }
}

Просмотреть файл

@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows.Input;
using Xamarin.Forms.Internals;
using Xamarin.Forms.Xaml.Diagnostics;
namespace Xamarin.Forms
{
@ -98,6 +99,8 @@ namespace Xamarin.Forms
_logicalChildren.Add(element);
element.Parent = this;
VisualDiagnostics.OnChildAdded(this, element);
}
public void RemoveLogicalChild(Element element)
@ -108,7 +111,12 @@ namespace Xamarin.Forms
}
element.Parent = null;
if (!_logicalChildren.Contains(element))
return;
var oldLogicalIndex = _logicalChildren.IndexOf(element);
_logicalChildren.Remove(element);
VisualDiagnostics.OnChildRemoved(this, element, oldLogicalIndex);
}
#if NETSTANDARD1_0

Просмотреть файл

@ -8,43 +8,38 @@ using Xamarin.Forms.Internals;
namespace Xamarin.Forms
{
[ContentProperty("Children")]
[ContentProperty(nameof(Children))]
public abstract class Layout<T> : Layout, IViewContainer<T> where T : View
{
readonly ElementCollection<T> _children;
protected Layout()
{
_children = new ElementCollection<T>(InternalChildren);
}
protected Layout() => _children = new ElementCollection<T>(InternalChildren);
public new IList<T> Children
{
get { return _children; }
}
protected virtual void OnAdded(T view)
{
}
public new IList<T> Children => _children;
protected override void OnChildAdded(Element child)
{
base.OnChildAdded(child);
var typedChild = child as T;
if (typedChild != null)
if (child is T typedChild)
OnAdded(typedChild);
}
protected override void OnChildRemoved(Element child)
{
base.OnChildRemoved(child);
[Obsolete("OnChildRemoved(Element) is obsolete as of version 4.8.0. Please use OnChildRemoved(Element, int) instead.")]
protected override void OnChildRemoved(Element child) => OnChildRemoved(child, -1);
var typedChild = child as T;
if (typedChild != null)
protected override void OnChildRemoved(Element child, int oldLogicalIndex)
{
base.OnChildRemoved(child, oldLogicalIndex);
if (child is T typedChild)
OnRemoved(typedChild);
}
protected virtual void OnAdded(T view)
{
}
protected virtual void OnRemoved(T view)
{
}
@ -52,10 +47,11 @@ namespace Xamarin.Forms
public abstract class Layout : View, ILayout, ILayoutController, IPaddingElement
{
public static readonly BindableProperty IsClippedToBoundsProperty = BindableProperty.Create("IsClippedToBounds", typeof(bool), typeof(Layout), false);
public static readonly BindableProperty IsClippedToBoundsProperty =
BindableProperty.Create(nameof(IsClippedToBounds), typeof(bool), typeof(Layout), false);
public static readonly BindableProperty CascadeInputTransparentProperty = BindableProperty.Create(
nameof(CascadeInputTransparent), typeof(bool), typeof(Layout), true);
public static readonly BindableProperty CascadeInputTransparentProperty =
BindableProperty.Create(nameof(CascadeInputTransparent), typeof(bool), typeof(Layout), true);
public static readonly BindableProperty PaddingProperty = PaddingElement.PaddingProperty;
@ -79,51 +75,36 @@ namespace Xamarin.Forms
public bool IsClippedToBounds
{
get { return (bool)GetValue(IsClippedToBoundsProperty); }
set { SetValue(IsClippedToBoundsProperty, value); }
get => (bool)GetValue(IsClippedToBoundsProperty);
set => SetValue(IsClippedToBoundsProperty, value);
}
public Thickness Padding
{
get { return (Thickness)GetValue(PaddingElement.PaddingProperty); }
set { SetValue(PaddingElement.PaddingProperty, value); }
get => (Thickness)GetValue(PaddingElement.PaddingProperty);
set => SetValue(PaddingElement.PaddingProperty, value);
}
public bool CascadeInputTransparent
{
get { return (bool)GetValue(CascadeInputTransparentProperty); }
set { SetValue(CascadeInputTransparentProperty, value); }
get => (bool)GetValue(CascadeInputTransparentProperty);
set => SetValue(CascadeInputTransparentProperty, value);
}
Thickness IPaddingElement.PaddingDefaultValueCreator()
{
return default(Thickness);
}
Thickness IPaddingElement.PaddingDefaultValueCreator() => default(Thickness);
void IPaddingElement.OnPaddingPropertyChanged(Thickness oldValue, Thickness newValue)
{
InvalidateLayout();
}
void IPaddingElement.OnPaddingPropertyChanged(Thickness oldValue, Thickness newValue) => InvalidateLayout();
internal ObservableCollection<Element> InternalChildren { get; } = new ObservableCollection<Element>();
internal override ReadOnlyCollection<Element> LogicalChildrenInternal
{
get { return _logicalChildren ?? (_logicalChildren = new ReadOnlyCollection<Element>(InternalChildren)); }
}
internal override ReadOnlyCollection<Element> LogicalChildrenInternal => _logicalChildren ?? (_logicalChildren = new ReadOnlyCollection<Element>(InternalChildren));
public event EventHandler LayoutChanged;
[EditorBrowsable(EditorBrowsableState.Never)]
public IReadOnlyList<Element> Children
{
get { return InternalChildren; }
}
public IReadOnlyList<Element> Children => InternalChildren;
public void ForceLayout()
{
SizeAllocated(Width, Height);
}
public void ForceLayout() => SizeAllocated(Width, Height);
[Obsolete("OnSizeRequest is obsolete as of version 2.2.0. Please use OnMeasure instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
@ -136,13 +117,11 @@ namespace Xamarin.Forms
public static void LayoutChildIntoBoundingRegion(VisualElement child, Rectangle region)
{
var parent = child.Parent as IFlowDirectionController;
bool isRightToLeft = false;
if (parent != null && (isRightToLeft = parent.ApplyEffectiveFlowDirectionToChildContainer && parent.EffectiveFlowDirection.IsRightToLeft()))
if (child.Parent is IFlowDirectionController parent && (isRightToLeft = parent.ApplyEffectiveFlowDirectionToChildContainer && parent.EffectiveFlowDirection.IsRightToLeft()))
region = new Rectangle(parent.Width - region.Right, region.Y, region.Width, region.Height);
var view = child as View;
if (view == null)
if (!(child is View view))
{
child.Layout(region);
return;
@ -224,15 +203,9 @@ namespace Xamarin.Forms
UpdateChildrenLayout();
}
protected virtual bool ShouldInvalidateOnChildAdded(View child)
{
return true;
}
protected virtual bool ShouldInvalidateOnChildAdded(View child) => true;
protected virtual bool ShouldInvalidateOnChildRemoved(View child)
{
return true;
}
protected virtual bool ShouldInvalidateOnChildRemoved(View child) => true;
protected void UpdateChildrenLayout()
{
@ -279,9 +252,8 @@ namespace Xamarin.Forms
internal static void LayoutChildIntoBoundingRegion(View child, Rectangle region, SizeRequest childSizeRequest)
{
var parent = child.Parent as IFlowDirectionController;
bool isRightToLeft = false;
if (parent != null && (isRightToLeft = parent.ApplyEffectiveFlowDirectionToChildContainer && parent.EffectiveFlowDirection.IsRightToLeft()))
if (child.Parent is IFlowDirectionController parent && (isRightToLeft = parent.ApplyEffectiveFlowDirectionToChildContainer && parent.EffectiveFlowDirection.IsRightToLeft()))
region = new Rectangle(parent.Width - region.Right, region.Y, region.Width, region.Height);
if (region.Size != childSizeRequest.Request)
@ -325,13 +297,11 @@ namespace Xamarin.Forms
int count = children.Count;
for (var index = 0; index < count; index++)
{
var v = LogicalChildrenInternal[index] as VisualElement;
if (v != null && v.IsVisible && (!v.IsPlatformEnabled || !v.IsNativeStateConsistent))
if (LogicalChildrenInternal[index] is VisualElement v && v.IsVisible && (!v.IsPlatformEnabled || !v.IsNativeStateConsistent))
return;
}
var view = child as View;
if (view != null)
if (child is View view)
{
// we can ignore the request if we are either fully constrained or when the size request changes and we were already fully constrainted
if ((trigger == InvalidationTrigger.MeasureChanged && view.Constraint == LayoutConstraint.Fixed) ||
@ -433,7 +403,7 @@ namespace Xamarin.Forms
if (v == null)
continue;
OnInternalRemoved(v);
OnInternalRemoved(v, e.OldStartingIndex + i);
}
}
@ -466,11 +436,11 @@ namespace Xamarin.Forms
view.MeasureInvalidated += OnChildMeasureInvalidated;
}
void OnInternalRemoved(View view)
void OnInternalRemoved(View view, int oldIndex)
{
view.MeasureInvalidated -= OnChildMeasureInvalidated;
OnChildRemoved(view);
OnChildRemoved(view, oldIndex);
if (ShouldInvalidateOnChildRemoved(view))
InvalidateLayout();
}

Просмотреть файл

@ -1,17 +1,30 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Windows.Input;
using Xamarin.Forms.Internals;
using Xamarin.Forms.Platform;
using Xamarin.Forms.Xaml.Diagnostics;
namespace Xamarin.Forms
{
[RenderWith(typeof(_ListViewRenderer))]
public class ListView : ItemsView<Cell>, IListViewController, IElementConfiguration<ListView>
{
readonly List<Element> _logicalChildren = new List<Element>();
#if NETSTANDARD1_0
ReadOnlyCollection<Element> _readOnlyLogicalChildren;
internal override ReadOnlyCollection<Element> LogicalChildrenInternal => _readOnlyLogicalChildren ??
(_readOnlyLogicalChildren = new ReadOnlyCollection<Element>(_logicalChildren));
#else
internal override ReadOnlyCollection<Element> LogicalChildrenInternal => _logicalChildren.AsReadOnly();
#endif
public static readonly BindableProperty IsPullToRefreshEnabledProperty = BindableProperty.Create("IsPullToRefreshEnabled", typeof(bool), typeof(ListView), false);
public static readonly BindableProperty IsRefreshingProperty = BindableProperty.Create("IsRefreshing", typeof(bool), typeof(ListView), false, BindingMode.TwoWay);
@ -108,17 +121,11 @@ namespace Xamarin.Forms
object bc = BindingContext;
var header = Header as Element;
if (header != null)
{
if (Header is Element header)
SetChildInheritedBindingContext(header, bc);
}
var footer = Footer as Element;
if (footer != null)
{
if (Footer is Element footer)
SetChildInheritedBindingContext(footer, bc);
}
}
public BindingBase GroupDisplayBinding
@ -384,17 +391,27 @@ namespace Xamarin.Forms
protected override void SetupContent(Cell content, int index)
{
base.SetupContent(content, index);
var viewCell = content as ViewCell;
if (viewCell != null && viewCell.View != null && HasUnevenRows)
if (content is ViewCell viewCell && viewCell.View != null && HasUnevenRows)
viewCell.View.ComputedConstraint = LayoutConstraint.None;
content.Parent = this;
if (content != null)
_logicalChildren.Add(content);
content.Parent = this;
VisualDiagnostics.OnChildAdded(this, content);
}
protected override void UnhookContent(Cell content)
{
base.UnhookContent(content);
if (content == null || !_logicalChildren.Contains(content))
return;
var index = _logicalChildren.IndexOf(content);
_logicalChildren.Remove(content);
content.Parent = null;
VisualDiagnostics.OnChildRemoved(this, content, index);
}
[EditorBrowsable(EditorBrowsableState.Never)]

Просмотреть файл

@ -472,12 +472,12 @@ namespace Xamarin.Forms
{
if (e.OldItems != null)
{
foreach (Element item in e.OldItems)
for (var i = 0; i < e.OldItems.Count; i++)
{
var item = (Element)e.OldItems[i];
if (item is VisualElement visual)
OnInternalRemoved(visual);
else
OnChildRemoved(item);
visual.MeasureInvalidated -= OnChildMeasureInvalidated;
OnChildRemoved(item, e.OldStartingIndex + i);
}
}
@ -501,13 +501,6 @@ namespace Xamarin.Forms
InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged);
}
void OnInternalRemoved(VisualElement view)
{
view.MeasureInvalidated -= OnChildMeasureInvalidated;
OnChildRemoved(view);
}
void OnPageBusyChanged()
{
if (!_hasAppeared)

Просмотреть файл

@ -972,7 +972,7 @@ namespace Xamarin.Forms
return;
if (_flyoutHeaderView != null)
OnChildRemoved(_flyoutHeaderView);
OnChildRemoved(_flyoutHeaderView, -1);
_flyoutHeaderView = value;
if (_flyoutHeaderView != null)
OnChildAdded(_flyoutHeaderView);

Просмотреть файл

@ -142,9 +142,12 @@ namespace Xamarin.Forms
}
}
protected override void OnChildRemoved(Element child)
[Obsolete("OnChildRemoved(Element) is obsolete as of version 4.8.0. Please use OnChildRemoved(Element, int) instead.")]
protected override void OnChildRemoved(Element child) => OnChildRemoved(child, -1);
protected override void OnChildRemoved(Element child, int oldLogicalIndex)
{
base.OnChildRemoved(child);
base.OnChildRemoved(child, oldLogicalIndex);
if (child is Page page)
{
page.PropertyChanged -= OnPagePropertyChanged;
@ -169,7 +172,7 @@ namespace Xamarin.Forms
var oldCache = _contentCache;
_contentCache = value;
if(oldCache != null)
OnChildRemoved(oldCache);
OnChildRemoved(oldCache, -1);
if (value != null && value.Parent != this)
{
@ -233,8 +236,11 @@ namespace Xamarin.Forms
OnChildAdded(el);
if (e.OldItems != null)
foreach (Element el in e.OldItems)
OnChildRemoved(el);
for (var i = 0; i < e.OldItems.Count; i++)
{
var el = (Element)e.OldItems[i];
OnChildRemoved(el, e.OldStartingIndex + i);
}
}
internal override void ApplyQueryAttributes(IDictionary<string, string> query)

Просмотреть файл

@ -257,9 +257,12 @@ namespace Xamarin.Forms
OnVisibleChildAdded(child);
}
protected override void OnChildRemoved(Element child)
[Obsolete("OnChildRemoved(Element) is obsolete as of version 4.8.0. Please use OnChildRemoved(Element, int) instead.")]
protected override void OnChildRemoved(Element child) => OnChildRemoved(child, -1);
protected override void OnChildRemoved(Element child, int oldLogicalIndex)
{
base.OnChildRemoved(child);
base.OnChildRemoved(child, oldLogicalIndex);
OnVisibleChildRemoved(child);
}
@ -317,8 +320,11 @@ namespace Xamarin.Forms
if (e.OldItems != null)
{
foreach (Element element in e.OldItems)
OnChildRemoved(element);
for (var i = 0; i < e.OldItems.Count; i++)
{
var element = (Element)e.OldItems[i];
OnChildRemoved(element, e.OldStartingIndex + i);
}
}
}

Просмотреть файл

@ -529,8 +529,11 @@ namespace Xamarin.Forms
base.OnChildAdded(child);
OnVisibleChildAdded(child);
}
protected override void OnChildRemoved(Element child)
[Obsolete("OnChildRemoved(Element) is obsolete as of version 4.8.0. Please use OnChildRemoved(Element, int) instead.")]
protected override void OnChildRemoved(Element child) => OnChildRemoved(child, -1);
protected override void OnChildRemoved(Element child, int oldLogicalIndex)
{
if(child is IShellContentController sc && sc.Page.IsPlatformEnabled)
{
@ -538,12 +541,12 @@ namespace Xamarin.Forms
void WaitForRendererToGetRemoved(object s, EventArgs p)
{
sc.Page.PlatformEnabledChanged -= WaitForRendererToGetRemoved;
base.OnChildRemoved(child);
base.OnChildRemoved(child, oldLogicalIndex);
};
}
else
{
base.OnChildRemoved(child);
base.OnChildRemoved(child, oldLogicalIndex);
}
OnVisibleChildRemoved(child);
@ -878,15 +881,21 @@ namespace Xamarin.Forms
if (e.OldItems != null)
{
foreach (Element element in e.OldItems)
OnChildRemoved(element);
for (var i = 0; i < e.OldItems.Count; i++)
{
var element = (Element)e.OldItems[i];
OnChildRemoved(element, e.OldStartingIndex + i);
}
}
}
void RemovePage(Page page)
{
if (_logicalChildren.Remove(page))
OnChildRemoved(page);
if (!_logicalChildren.Contains(page))
return;
var index = _logicalChildren.IndexOf(page);
_logicalChildren.Remove(page);
OnChildRemoved(page, index);
}
void SendAppearanceChanged() => ((IShellController)Parent?.Parent)?.AppearanceChanged(this, false);

Просмотреть файл

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
namespace Xamarin.Forms
@ -56,9 +57,12 @@ namespace Xamarin.Forms
{
}
protected override void OnChildRemoved(Element child)
[Obsolete("OnChildRemoved(Element) is obsolete as of version 4.8.0. Please use OnChildRemoved(Element, int) instead.")]
protected override void OnChildRemoved(Element child) => OnChildRemoved(child, -1);
protected override void OnChildRemoved(Element child, int oldLogicalIndex)
{
base.OnChildRemoved(child);
base.OnChildRemoved(child, oldLogicalIndex);
TemplateUtilities.OnChildRemoved(this, child);
}

Просмотреть файл

@ -87,9 +87,12 @@ namespace Xamarin.Forms
{
}
protected override void OnChildRemoved(Element child)
[Obsolete("OnChildRemoved(Element) is obsolete as of version 4.8.0. Please use OnChildRemoved(Element, int) instead.")]
protected override void OnChildRemoved(Element child) => OnChildRemoved(child, -1);
protected override void OnChildRemoved(Element child, int oldLogicalIndex)
{
base.OnChildRemoved(child);
base.OnChildRemoved(child, oldLogicalIndex);
TemplateUtilities.OnChildRemoved(this, child);
}

Просмотреть файл

@ -73,10 +73,7 @@ namespace Xamarin.Forms
set { SetValue(VisualProperty, value); }
}
internal static void SetDefaultVisual(IVisual visual)
{
_defaultVisual = visual;
}
internal static void SetDefaultVisual(IVisual visual) => _defaultVisual = visual;
IVisual IVisualController.EffectiveVisual
{
@ -271,11 +268,8 @@ namespace Xamarin.Forms
EffectiveFlowDirection _effectiveFlowDirection = default(EffectiveFlowDirection);
EffectiveFlowDirection IFlowDirectionController.EffectiveFlowDirection
{
get { return _effectiveFlowDirection; }
set
{
SetEffectiveFlowDirection(value, true);
}
get => _effectiveFlowDirection;
set => SetEffectiveFlowDirection(value, true);
}
void SetEffectiveFlowDirection(EffectiveFlowDirection value, bool fireFlowDirectionPropertyChanged)
@ -389,10 +383,7 @@ namespace Xamarin.Forms
set { SetValue(IsEnabledProperty, value); }
}
public bool IsFocused
{
get { return (bool)GetValue(IsFocusedProperty); }
}
public bool IsFocused => (bool)GetValue(IsFocusedProperty);
[TypeConverter(typeof(VisibilityConverter))]
public bool IsVisible
@ -487,10 +478,7 @@ namespace Xamarin.Forms
set { SetValue(TranslationYProperty, value); }
}
public IList<TriggerBase> Triggers
{
get { return (IList<TriggerBase>)GetValue(TriggersProperty); }
}
public IList<TriggerBase> Triggers => (IList<TriggerBase>)GetValue(TriggersProperty);
public double Width
{
@ -524,10 +512,7 @@ namespace Xamarin.Forms
}
[EditorBrowsable(EditorBrowsableState.Never)]
public bool Batched
{
get { return _batched > 0; }
}
public bool Batched => _batched > 0;
internal LayoutConstraint ComputedConstraint
{
@ -545,10 +530,7 @@ namespace Xamarin.Forms
}
}
internal LayoutConstraint Constraint
{
get { return ComputedConstraint | SelfConstraint; }
}
internal LayoutConstraint Constraint => ComputedConstraint | SelfConstraint;
[EditorBrowsable(EditorBrowsableState.Never)]
public bool DisableLayout { get; set; }
@ -629,10 +611,7 @@ namespace Xamarin.Forms
}
}
public void BatchBegin()
{
_batched++;
}
public void BatchBegin() => _batched++;
public void BatchCommit()
{
@ -670,10 +649,7 @@ namespace Xamarin.Forms
}
[EditorBrowsable(EditorBrowsableState.Never)]
public void NativeSizeChanged()
{
InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged);
}
public void NativeSizeChanged() => InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged);
public event EventHandler ChildrenReordered;
@ -696,12 +672,9 @@ namespace Xamarin.Forms
[EditorBrowsable(EditorBrowsableState.Never)]
public virtual SizeRequest GetSizeRequest(double widthConstraint, double heightConstraint)
{
SizeRequest cachedResult;
var constraintSize = new Size(widthConstraint, heightConstraint);
if (_measureCache.TryGetValue(constraintSize, out cachedResult))
{
if (_measureCache.TryGetValue(constraintSize, out SizeRequest cachedResult))
return cachedResult;
}
double widthRequest = WidthRequest;
double heightRequest = HeightRequest;
@ -743,17 +716,12 @@ namespace Xamarin.Forms
var r = new SizeRequest(request, minimum);
if (r.Request.Width > 0 && r.Request.Height > 0)
{
_measureCache[constraintSize] = r;
}
return r;
}
public void Layout(Rectangle bounds)
{
Bounds = bounds;
}
public void Layout(Rectangle bounds) => Bounds = bounds;
public SizeRequest Measure(double widthConstraint, double heightConstraint, MeasureFlags flags = MeasureFlags.None)
{
@ -761,8 +729,7 @@ namespace Xamarin.Forms
Thickness margin = default(Thickness);
if (includeMargins)
{
var view = this as View;
if (view != null)
if (this is View view)
margin = view.Margin;
widthConstraint = Math.Max(0, widthConstraint - margin.HorizontalThickness);
heightConstraint = Math.Max(0, heightConstraint - margin.VerticalThickness);
@ -771,13 +738,10 @@ namespace Xamarin.Forms
SizeRequest result = GetSizeRequest(widthConstraint, heightConstraint);
#pragma warning restore 0618
if (includeMargins)
if (includeMargins && !margin.IsEmpty)
{
if (!margin.IsEmpty)
{
result.Minimum = new Size(result.Minimum.Width + margin.HorizontalThickness, result.Minimum.Height + margin.VerticalThickness);
result.Request = new Size(result.Request.Width + margin.HorizontalThickness, result.Request.Height + margin.VerticalThickness);
}
result.Minimum = new Size(result.Minimum.Width + margin.HorizontalThickness, result.Minimum.Height + margin.VerticalThickness);
result.Request = new Size(result.Request.Width + margin.HorizontalThickness, result.Request.Height + margin.VerticalThickness);
}
return result;
@ -792,19 +756,12 @@ namespace Xamarin.Forms
if (!IsFocused)
return;
EventHandler<FocusRequestArgs> unfocus = FocusChangeRequested;
if (unfocus != null)
{
unfocus(this, new FocusRequestArgs());
}
FocusChangeRequested?.Invoke(this, new FocusRequestArgs());
}
public event EventHandler<FocusEventArgs> Unfocused;
protected virtual void InvalidateMeasure()
{
InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged);
}
protected virtual void InvalidateMeasure() => InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged);
protected override void OnBindingContextChanged()
{
@ -820,11 +777,13 @@ namespace Xamarin.Forms
ComputeConstraintForView(view);
}
protected override void OnChildRemoved(Element child)
[Obsolete("OnChildRemoved(Element) is obsolete as of version 4.8.0. Please use OnChildRemoved(Element, int) instead.")]
protected override void OnChildRemoved(Element child) => OnChildRemoved(child, -1);
protected override void OnChildRemoved(Element child, int oldLogicalIndex)
{
base.OnChildRemoved(child);
var view = child as View;
if (view != null)
base.OnChildRemoved(child, oldLogicalIndex);
if (child is View view)
view.ComputedConstraint = LayoutConstraint.None;
}
@ -847,17 +806,12 @@ namespace Xamarin.Forms
protected virtual SizeRequest OnSizeRequest(double widthConstraint, double heightConstraint)
{
if (!IsPlatformEnabled)
{
return new SizeRequest(new Size(-1, -1));
}
return Device.PlatformServices.GetNativeSize(this, widthConstraint, heightConstraint);
}
protected void SizeAllocated(double width, double height)
{
OnSizeAllocated(width, height);
}
protected void SizeAllocated(double width, double height) => OnSizeAllocated(width, height);
[EditorBrowsable(EditorBrowsableState.Never)]
public event EventHandler<EventArg<VisualElement>> BatchCommitted;
@ -866,16 +820,12 @@ namespace Xamarin.Forms
{
for (var i = 0; i < LogicalChildrenInternal.Count; i++)
{
var child = LogicalChildrenInternal[i] as View;
if (child != null)
if (LogicalChildrenInternal[i] is View child)
ComputeConstraintForView(child);
}
}
internal virtual void ComputeConstraintForView(View view)
{
view.ComputedConstraint = LayoutConstraint.None;
}
internal virtual void ComputeConstraintForView(View view) => view.ComputedConstraint = LayoutConstraint.None;
[EditorBrowsable(EditorBrowsableState.Never)]
public event EventHandler<FocusRequestArgs> FocusChangeRequested;
@ -891,10 +841,7 @@ namespace Xamarin.Forms
MeasureInvalidated?.Invoke(this, new InvalidationEventArgs(trigger));
}
void IVisualElementController.InvalidateMeasure(InvalidationTrigger trigger)
{
InvalidateMeasureInternal(trigger);
}
void IVisualElementController.InvalidateMeasure(InvalidationTrigger trigger) => InvalidateMeasureInternal(trigger);
internal void InvalidateStateTriggers(bool attach)
{
@ -929,19 +876,13 @@ namespace Xamarin.Forms
#endif
}
internal virtual void OnConstraintChanged(LayoutConstraint oldConstraint, LayoutConstraint newConstraint)
{
ComputeConstrainsForChildren();
}
internal virtual void OnConstraintChanged(LayoutConstraint oldConstraint, LayoutConstraint newConstraint) => ComputeConstrainsForChildren();
internal virtual void OnIsPlatformEnabledChanged()
{
}
internal virtual void OnIsVisibleChanged(bool oldValue, bool newValue)
{
InvalidateMeasureInternal(InvalidationTrigger.Undefined);
}
internal virtual void OnIsVisibleChanged(bool oldValue, bool newValue) => InvalidateMeasureInternal(InvalidationTrigger.Undefined);
internal override void OnParentResourcesChanged(IEnumerable<KeyValuePair<string, object>> values)
{
@ -973,10 +914,7 @@ namespace Xamarin.Forms
OnResourcesChanged(changedResources);
}
internal void UnmockBounds()
{
_mockX = _mockY = _mockWidth = _mockHeight = -1;
}
internal void UnmockBounds() => _mockX = _mockY = _mockWidth = _mockHeight = -1;
void PropagateBindingContextToStateTriggers()
{
@ -991,30 +929,18 @@ namespace Xamarin.Forms
SetInheritedBindingContext(stateTrigger, BindingContext);
}
void OnFocused()
{
EventHandler<FocusEventArgs> focus = Focused;
if (focus != null)
focus(this, new FocusEventArgs(this, true));
}
void OnFocused() => Focused?.Invoke(this, new FocusEventArgs(this, true));
internal void ChangeVisualStateInternal() => ChangeVisualState();
protected internal virtual void ChangeVisualState()
{
if (!IsEnabled)
{
VisualStateManager.GoToState(this, VisualStateManager.CommonStates.Disabled);
}
else if (IsFocused)
{
VisualStateManager.GoToState(this, VisualStateManager.CommonStates.Focused);
}
else
{
VisualStateManager.GoToState(this, VisualStateManager.CommonStates.Normal);
}
}
static void OnVisualChanged(BindableObject bindable, object oldValue, object newValue)
@ -1056,11 +982,7 @@ namespace Xamarin.Forms
var element = (VisualElement)bindable;
if (element == null)
{
return;
}
var isEnabled = (bool)newValue;
element.ChangeVisualState();
}
@ -1104,16 +1026,10 @@ namespace Xamarin.Forms
((VisualElement)bindable).InvalidateMeasureInternal(InvalidationTrigger.SizeRequestChanged);
}
void OnUnfocus()
{
EventHandler<FocusEventArgs> unFocus = Unfocused;
if (unFocus != null)
unFocus(this, new FocusEventArgs(this, false));
}
void OnUnfocus() => Unfocused?.Invoke(this, new FocusEventArgs(this, false));
bool IFlowDirectionController.ApplyEffectiveFlowDirectionToChildContainer => true;
void IPropertyPropagationController.PropagatePropertyChanged(string propertyName)
{
PropertyPropagationExtensions.PropagatePropertyChanged(propertyName, this, LogicalChildren);
@ -1145,19 +1061,18 @@ namespace Xamarin.Forms
value = value?.Trim();
if (!string.IsNullOrEmpty(value))
{
if (value.Equals(Boolean.TrueString, StringComparison.OrdinalIgnoreCase))
if (value.Equals(bool.TrueString, StringComparison.OrdinalIgnoreCase))
return true;
if (value.Equals("visible", StringComparison.OrdinalIgnoreCase))
return true;
if (value.Equals(Boolean.FalseString, StringComparison.OrdinalIgnoreCase))
if (value.Equals(bool.FalseString, StringComparison.OrdinalIgnoreCase))
return false;
if (value.Equals("hidden", StringComparison.OrdinalIgnoreCase))
return false;
if (value.Equals("collapse", StringComparison.OrdinalIgnoreCase))
return false;
}
throw new InvalidOperationException(string.Format("Cannot convert \"{0}\" into {1}", value, typeof(bool)));
throw new InvalidOperationException(string.Format("Cannot convert \"{0}\" into {1}.", value, typeof(bool)));
}
}
}

Просмотреть файл

@ -4,6 +4,7 @@
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using Xamarin.Forms.Internals;
namespace Xamarin.Forms.Xaml.Diagnostics
{
@ -19,10 +20,33 @@ namespace Xamarin.Forms.Xaml.Diagnostics
}
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("use OnChildAdded/Removed")]
internal static void SendVisualTreeChanged(object parent, object child)
{
if (DebuggerHelper.DebuggerIsAttached)
VisualTreeChanged?.Invoke(parent, new VisualTreeChangeEventArgs(parent, child, -1, child != null ? VisualTreeChangeType.Add : VisualTreeChangeType.Remove));
if (!DebuggerHelper.DebuggerIsAttached)
return;
VisualTreeChanged?.Invoke(parent, new VisualTreeChangeEventArgs(parent, child, -1, child != null ? VisualTreeChangeType.Add : VisualTreeChangeType.Remove));
}
internal static void OnChildAdded(Element parent, Element child)
{
if (!DebuggerHelper.DebuggerIsAttached)
return;
if (child is null)
return;
var index = parent?.AllChildren.IndexOf(child) ?? -1;
VisualTreeChanged?.Invoke(parent, new VisualTreeChangeEventArgs(parent, child, index, VisualTreeChangeType.Add));
}
internal static void OnChildRemoved(Element parent, Element child, int oldLogicalIndex)
{
if (!DebuggerHelper.DebuggerIsAttached)
return;
VisualTreeChanged?.Invoke(parent, new VisualTreeChangeEventArgs(parent, child, oldLogicalIndex, VisualTreeChangeType.Remove));
}
public static event EventHandler<VisualTreeChangeEventArgs> VisualTreeChanged;

Просмотреть файл

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Xamarin.Forms.Xaml.UnitTests.Gh11334">
<StackLayout x:Name="stack">
<Label x:Name="label" Text="Welcome to Xamarin.Forms!!!!"
HorizontalOptions="Start"
VerticalOptions="CenterAndExpand" />
<StackLayout Orientation="Horizontal" HorizontalOptions="FillAndExpand">
<Button Margin="5" Text="Remove" Clicked="Remove" />
<Button Margin="5" Text="Add" Clicked="Add" />
</StackLayout>
</StackLayout>
</ContentPage>

Просмотреть файл

@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using NUnit.Framework;
using Xamarin.Forms;
using Xamarin.Forms.Core.UnitTests;
using Xamarin.Forms.Xaml.Diagnostics;
namespace Xamarin.Forms.Xaml.UnitTests
{
public partial class Gh11334 : ContentPage
{
public Gh11334()
{
InitializeComponent();
}
public Gh11334(bool useCompiledXaml)
{
//this stub will be replaced at compile time
}
void Remove(object sender, EventArgs e) => stack.Children.Remove(label);
void Add(object sender, EventArgs e)
{
int index = stack.Children.IndexOf(label);
Label newLabel = new Label { Text = "New Inserted Label" };
stack.Children.Insert(index + 1, newLabel);
}
[TestFixture]
class Tests
{
bool _debuggerinitialstate;
[SetUp]
public void Setup()
{
Device.PlatformServices = new MockPlatformServices();
_debuggerinitialstate = Xamarin.Forms.Xaml.Diagnostics.DebuggerHelper._mockDebuggerIsAttached;
DebuggerHelper._mockDebuggerIsAttached = true;
}
[TearDown]
public void TearDown()
{
DebuggerHelper._mockDebuggerIsAttached = _debuggerinitialstate;
Device.PlatformServices = null;
VisualDiagnostics.VisualTreeChanged -= OnVTChanged;
}
void OnVTChanged(object sender, VisualTreeChangeEventArgs e)
{
Assert.That(e.ChangeType, Is.EqualTo(VisualTreeChangeType.Remove));
Assert.That(e.ChildIndex, Is.EqualTo(0));
Assert.Pass();
}
[Test]
public void ChildIndexOnRemove([Values(false, true)] bool useCompiledXaml)
{
var layout = new Gh11334(useCompiledXaml);
VisualDiagnostics.VisualTreeChanged += OnVTChanged;
layout.Remove(null, EventArgs.Empty);
Assert.Fail();
}
}
}
}

Просмотреть файл

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Xamarin.Forms.Xaml.UnitTests.Gh11335">
<StackLayout x:Name="stack">
<Label x:Name="label" Text="Welcome to Xamarin.Forms!!!!"
HorizontalOptions="Start"
VerticalOptions="CenterAndExpand" />
<StackLayout Orientation="Horizontal" HorizontalOptions="FillAndExpand">
<Button Margin="5" Text="Remove" Clicked="Remove" />
<Button Margin="5" Text="Add" Clicked="Add" />
</StackLayout>
</StackLayout>
</ContentPage>

Просмотреть файл

@ -0,0 +1,63 @@
using System;
using NUnit.Framework;
using Xamarin.Forms.Core.UnitTests;
using Xamarin.Forms.Xaml.Diagnostics;
namespace Xamarin.Forms.Xaml.UnitTests
{
public partial class Gh11335 : ContentPage
{
public Gh11335() => InitializeComponent();
public Gh11335(bool useCompiledXaml)
{
//this stub will be replaced at compile time
}
void Remove(object sender, EventArgs e) => stack.Children.Remove(label);
void Add(object sender, EventArgs e)
{
int index = stack.Children.IndexOf(label);
Label newLabel = new Label { Text = "New Inserted Label" };
stack.Children.Insert(index + 1, newLabel);
}
[TestFixture]
class Tests
{
bool _debuggerinitialstate;
[SetUp]
public void Setup()
{
Device.PlatformServices = new MockPlatformServices();
_debuggerinitialstate = Xamarin.Forms.Xaml.Diagnostics.DebuggerHelper._mockDebuggerIsAttached;
DebuggerHelper._mockDebuggerIsAttached = true;
}
[TearDown]
public void TearDown()
{
DebuggerHelper._mockDebuggerIsAttached = _debuggerinitialstate;
Device.PlatformServices = null;
VisualDiagnostics.VisualTreeChanged -= OnVTChanged;
}
void OnVTChanged(object sender, VisualTreeChangeEventArgs e)
{
Assert.That(e.ChangeType, Is.EqualTo(VisualTreeChangeType.Add));
Assert.That(e.ChildIndex, Is.EqualTo(1));
Assert.Pass();
}
[Test]
public void ChildIndexOnAdd([Values(false, true)] bool useCompiledXaml)
{
var layout = new Gh11335(useCompiledXaml);
VisualDiagnostics.VisualTreeChanged += OnVTChanged;
layout.Add(null, EventArgs.Empty);
Assert.Fail();
}
}
}
}

Просмотреть файл

@ -102,7 +102,7 @@ namespace Xamarin.Forms.Xaml
ExceptionHandler = doNotThrow ? ehandler : (Action<Exception>)null
}, useDesignProperties);
VisualDiagnostics.SendVisualTreeChanged(null, view);
VisualDiagnostics.OnChildAdded(null, view as Element);
break;
}
@ -143,7 +143,7 @@ namespace Xamarin.Forms.Xaml
visitorContext.RootElement = inflatedView as BindableObject;
Visit(rootnode, visitorContext, useDesignProperties);
VisualDiagnostics.SendVisualTreeChanged(null, inflatedView);
VisualDiagnostics.OnChildAdded(null, inflatedView as Element);
break;
}
}