[C] index on VTChanges (#11775)
* [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:
Родитель
16b290ae8d
Коммит
975577e837
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче