diff --git a/src/Avalonia.Controls/Presenters/CarouselPresenter.cs b/src/Avalonia.Controls/Presenters/CarouselPresenter.cs
index 70a7583daf..7888249bdd 100644
--- a/src/Avalonia.Controls/Presenters/CarouselPresenter.cs
+++ b/src/Avalonia.Controls/Presenters/CarouselPresenter.cs
@@ -155,6 +155,11 @@ namespace Avalonia.Controls.Presenters
}
}
+ protected override void PanelCreated(IPanel panel)
+ {
+ ItemsChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
+ }
+
///
/// Moves to the selected page, animating if a is set.
///
diff --git a/src/Avalonia.Controls/Presenters/ItemsPresenterBase.cs b/src/Avalonia.Controls/Presenters/ItemsPresenterBase.cs
index 23846bcd2e..52f173fc71 100644
--- a/src/Avalonia.Controls/Presenters/ItemsPresenterBase.cs
+++ b/src/Avalonia.Controls/Presenters/ItemsPresenterBase.cs
@@ -229,8 +229,6 @@ namespace Avalonia.Controls.Presenters
}
PanelCreated(Panel);
-
- ItemsChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
///
diff --git a/src/Avalonia.Controls/RelativePanel.AttachedProperties.cs b/src/Avalonia.Controls/RelativePanel.AttachedProperties.cs
index f93de5ca15..f64c26682b 100644
--- a/src/Avalonia.Controls/RelativePanel.AttachedProperties.cs
+++ b/src/Avalonia.Controls/RelativePanel.AttachedProperties.cs
@@ -33,7 +33,7 @@ namespace Avalonia.Controls
AlignVerticalCenterWithProperty.Changed.AddClassHandler(OnAlignPropertiesChanged);
BelowProperty.Changed.AddClassHandler(OnAlignPropertiesChanged);
LeftOfProperty.Changed.AddClassHandler(OnAlignPropertiesChanged);
- LeftOfProperty.Changed.AddClassHandler(OnAlignPropertiesChanged);
+ RightOfProperty.Changed.AddClassHandler(OnAlignPropertiesChanged);
}
///
diff --git a/src/Avalonia.Controls/RelativePanel.cs b/src/Avalonia.Controls/RelativePanel.cs
index 033a5559f5..a3ad30db76 100644
--- a/src/Avalonia.Controls/RelativePanel.cs
+++ b/src/Avalonia.Controls/RelativePanel.cs
@@ -1,4 +1,4 @@
-/// Ported from https://github.com/HandyOrg/HandyControl/blob/master/src/Shared/HandyControl_Shared/Controls/Panel/RelativePanel.cs
+// Ported from https://github.com/HandyOrg/HandyControl/blob/master/src/Shared/HandyControl_Shared/Controls/Panel/RelativePanel.cs
using System;
using System.Collections.Generic;
using System.Linq;
@@ -14,25 +14,28 @@ namespace Avalonia.Controls
public RelativePanel() => _childGraph = new Graph();
- protected override Size MeasureOverride(Size availableSize)
+ private Layoutable? GetDependencyElement(AvaloniaProperty property, AvaloniaObject child)
{
- foreach (var child in Children)
+ var dependency = child.GetValue(property);
+
+ if (dependency is Layoutable layoutable)
{
- child?.Measure(availableSize);
+ if (Children.Contains((ILayoutable)layoutable))
+ return layoutable;
+
+ throw new ArgumentException($"RelativePanel error: Element does not exist in the current context: {property.Name}");
}
- return availableSize;
+ return null;
}
- protected override Size ArrangeOverride(Size arrangeSize)
+ protected override Size MeasureOverride(Size availableSize)
{
- _childGraph.Reset(arrangeSize);
-
- foreach (var child in Children.OfType())
+ _childGraph.Clear();
+ foreach (Layoutable child in Children)
{
if (child == null)
continue;
-
var node = _childGraph.AddNode(child);
node.AlignLeftWithNode = _childGraph.AddLink(node, GetDependencyElement(AlignLeftWithProperty, child));
@@ -47,63 +50,44 @@ namespace Avalonia.Controls
node.AlignHorizontalCenterWith = _childGraph.AddLink(node, GetDependencyElement(AlignHorizontalCenterWithProperty, child));
node.AlignVerticalCenterWith = _childGraph.AddLink(node, GetDependencyElement(AlignVerticalCenterWithProperty, child));
- }
- if (_childGraph.CheckCyclic())
- {
- throw new Exception("RelativePanel error: Circular dependency detected. Layout could not complete.");
}
+ _childGraph.Measure(availableSize);
- var size = new Size();
-
- foreach (var child in Children)
- {
- if (child.Bounds.Bottom > size.Height)
- {
- size = size.WithHeight(child.Bounds.Bottom);
- }
+ _childGraph.Reset();
+ var boundingSize = _childGraph.GetBoundingSize(Width.IsNaN(), Height.IsNaN());
+ _childGraph.Reset();
+ _childGraph.Measure(boundingSize);
+ return boundingSize;
+ }
- if (child.Bounds.Right > size.Width)
- {
- size = size.WithWidth(child.Bounds.Right);
- }
- }
+ protected override Size ArrangeOverride(Size arrangeSize)
+ {
+ _childGraph.GetNodes().Do(node => node.Arrange(arrangeSize));
+ return arrangeSize;
+ }
- if (VerticalAlignment == VerticalAlignment.Stretch)
- {
- size = size.WithHeight(arrangeSize.Height);
- }
+ private class GraphNode
+ {
+ public bool Measured { get; set; }
- if (HorizontalAlignment == HorizontalAlignment.Stretch)
- {
- size = size.WithWidth(arrangeSize.Width);
- }
+ public Layoutable Element { get; }
- return size;
- }
+ private bool HorizontalOffsetFlag { get; set; }
- private Layoutable? GetDependencyElement(AvaloniaProperty property, AvaloniaObject child)
- {
- var dependency = child.GetValue(property);
+ private bool VerticalOffsetFlag { get; set; }
- if (dependency is Layoutable layoutable)
- {
- if (Children.Contains((ILayoutable)layoutable))
- return layoutable;
+ private Size BoundingSize { get; set; }
- throw new ArgumentException($"RelativePanel error: Element does not exist in the current context: {property.Name}");
- }
+ public Size OriginDesiredSize { get; set; }
- return null;
- }
+ public double Left { get; set; } = double.NaN;
- private class GraphNode
- {
- public Point Position { get; set; }
+ public double Top { get; set; } = double.NaN;
- public bool Arranged { get; set; }
+ public double Right { get; set; } = double.NaN;
- public Layoutable Element { get; }
+ public double Bottom { get; set; } = double.NaN;
public HashSet OutgoingNodes { get; }
@@ -132,19 +116,101 @@ namespace Avalonia.Controls
OutgoingNodes = new HashSet();
Element = element;
}
+
+ public void Arrange(Size arrangeSize) => Element.Arrange(new Rect(Left, Top, Math.Max(arrangeSize.Width - Left - Right, 0), Math.Max(arrangeSize.Height - Top - Bottom, 0)));
+
+ public void Reset()
+ {
+ Left = double.NaN;
+ Top = double.NaN;
+ Right = double.NaN;
+ Bottom = double.NaN;
+ Measured = false;
+ }
+
+ public Size GetBoundingSize()
+ {
+ if (Measured)
+ return BoundingSize;
+
+ if (!OutgoingNodes.Any())
+ {
+ BoundingSize = Element.DesiredSize;
+ Measured = true;
+ }
+ else
+ {
+ BoundingSize = GetBoundingSize(this, Element.DesiredSize, OutgoingNodes);
+ Measured = true;
+ }
+
+ return BoundingSize;
+ }
+
+ private static Size GetBoundingSize(GraphNode prevNode, Size prevSize, IEnumerable nodes)
+ {
+ foreach (var node in nodes)
+ {
+ if (node.Measured || !node.OutgoingNodes.Any())
+ {
+ if (prevNode.LeftOfNode != null && prevNode.LeftOfNode == node ||
+ prevNode.RightOfNode != null && prevNode.RightOfNode == node)
+ {
+ prevSize = prevSize.WithWidth(prevSize.Width + node.BoundingSize.Width);
+ if (GetAlignHorizontalCenterWithPanel(node.Element) || node.HorizontalOffsetFlag)
+ {
+ prevSize = prevSize.WithWidth(prevSize.Width + prevNode.OriginDesiredSize.Width);
+ prevNode.HorizontalOffsetFlag = true;
+ }
+ if (node.VerticalOffsetFlag)
+ {
+ prevNode.VerticalOffsetFlag = true;
+ }
+ }
+
+ if (prevNode.AboveNode != null && prevNode.AboveNode == node ||
+ prevNode.BelowNode != null && prevNode.BelowNode == node)
+ {
+ prevSize = prevSize.WithHeight(prevSize.Height + node.BoundingSize.Height);
+ if (GetAlignVerticalCenterWithPanel(node.Element) || node.VerticalOffsetFlag)
+ {
+ prevSize = prevSize.WithHeight(prevSize.Height + node.OriginDesiredSize.Height);
+ prevNode.VerticalOffsetFlag = true;
+ }
+ if (node.HorizontalOffsetFlag)
+ {
+ prevNode.HorizontalOffsetFlag = true;
+ }
+ }
+ }
+ else
+ {
+ return GetBoundingSize(node, prevSize, node.OutgoingNodes);
+ }
+ }
+
+ return prevSize;
+ }
}
private class Graph
{
private readonly Dictionary _nodeDic;
- private Size _arrangeSize;
+ private Size AvailableSize { get; set; }
- public Graph()
+ public Graph() => _nodeDic = new Dictionary();
+
+ public IEnumerable GetNodes() => _nodeDic.Values;
+
+ public void Clear()
{
- _nodeDic = new Dictionary();
+ AvailableSize = new Size();
+ _nodeDic.Clear();
}
+ public void Reset() => _nodeDic.Values.Do(node => node.Reset());
+
public GraphNode? AddLink(GraphNode from, Layoutable? to)
{
if (to == null)
@@ -177,177 +243,296 @@ namespace Avalonia.Controls
return _nodeDic[value];
}
- public void Reset(Size arrangeSize)
+ public void Measure(Size availableSize)
{
- _arrangeSize = arrangeSize;
- _nodeDic.Clear();
+ AvailableSize = availableSize;
+ Measure(_nodeDic.Values, null);
}
- public bool CheckCyclic() => CheckCyclic(_nodeDic.Values, null);
-
- private bool CheckCyclic(IEnumerable nodes, HashSet? set)
+ private void Measure(IEnumerable nodes, HashSet? set)
{
- set ??= new HashSet();
+ set ??= new HashSet();
foreach (var node in nodes)
{
- if (!node.Arranged && node.OutgoingNodes.Count == 0)
+ /*
+ * 该节点无任何依赖,所以从这里开始计算元素位置。
+ * 因为无任何依赖,所以忽略同级元素
+ */
+ if (!node.Measured && !node.OutgoingNodes.Any())
{
- ArrangeChild(node, true);
+ MeasureChild(node);
continue;
}
- if (node.OutgoingNodes.All(item => item.Arranged))
+ // 判断依赖元素是否全部排列完毕
+ if (node.OutgoingNodes.All(item => item.Measured))
{
- ArrangeChild(node);
+ MeasureChild(node);
continue;
}
+ // 判断是否有循环
if (!set.Add(node.Element))
- return true;
+ throw new Exception("RelativePanel error: Circular dependency detected. Layout could not complete.");
- return CheckCyclic(node.OutgoingNodes, set);
- }
+ // 没有循环,且有依赖,则继续往下
+ Measure(node.OutgoingNodes, set);
- return false;
+ if (!node.Measured)
+ {
+ MeasureChild(node);
+ }
+ }
}
- private void ArrangeChild(GraphNode node, bool ignoneSibling = false)
+ private void MeasureChild(GraphNode node)
{
var child = node.Element;
- var childSize = child.DesiredSize;
- var childPos = new Point();
+ child.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
+ node.OriginDesiredSize = child.DesiredSize;
- if (GetAlignHorizontalCenterWithPanel(child))
+ var alignLeftWithPanel = GetAlignLeftWithPanel(child);
+ var alignTopWithPanel = GetAlignTopWithPanel(child);
+ var alignRightWithPanel = GetAlignRightWithPanel(child);
+ var alignBottomWithPanel = GetAlignBottomWithPanel(child);
+
+ if (alignLeftWithPanel)
+ node.Left = 0;
+ if (alignTopWithPanel)
+ node.Top = 0;
+ if (alignRightWithPanel)
+ node.Right = 0;
+ if (alignBottomWithPanel)
+ node.Bottom = 0;
+
+ if (node.AlignLeftWithNode != null)
{
- childPos = childPos.WithX((_arrangeSize.Width - childSize.Width) / 2);
+ node.Left = node.Left.IsNaN() ? node.AlignLeftWithNode.Left : node.AlignLeftWithNode.Left * 0.5;
}
- if (GetAlignVerticalCenterWithPanel(child))
+ if (node.AlignTopWithNode != null)
{
- childPos = childPos.WithY((_arrangeSize.Height - childSize.Height) / 2);
+ node.Top = node.Top.IsNaN() ? node.AlignTopWithNode.Top : node.AlignTopWithNode.Top * 0.5;
}
- var alignLeftWithPanel = GetAlignLeftWithPanel(child);
- var alignTopWithPanel = GetAlignTopWithPanel(child);
- var alignRightWithPanel = GetAlignRightWithPanel(child);
- var alignBottomWithPanel = GetAlignBottomWithPanel(child);
+ if (node.AlignRightWithNode != null)
+ {
+ node.Right = node.Right.IsNaN()
+ ? node.AlignRightWithNode.Right
+ : node.AlignRightWithNode.Right * 0.5;
+ }
- if (!ignoneSibling)
+ if (node.AlignBottomWithNode != null)
{
- if (node.LeftOfNode != null)
- {
- childPos = childPos.WithX(node.LeftOfNode.Position.X - childSize.Width);
- }
+ node.Bottom = node.Bottom.IsNaN()
+ ? node.AlignBottomWithNode.Bottom
+ : node.AlignBottomWithNode.Bottom * 0.5;
+ }
- if (node.AboveNode != null)
- {
- childPos = childPos.WithY(node.AboveNode.Position.Y - childSize.Height);
- }
+ var availableHeight = AvailableSize.Height - node.Top - node.Bottom;
+ if (availableHeight.IsNaN())
+ {
+ availableHeight = AvailableSize.Height;
- if (node.RightOfNode != null)
+ if (!node.Top.IsNaN() && node.Bottom.IsNaN())
{
- childPos = childPos.WithX(node.RightOfNode.Position.X + node.RightOfNode.Element.DesiredSize.Width);
+ availableHeight -= node.Top;
}
-
- if (node.BelowNode != null)
+ else if (node.Top.IsNaN() && !node.Bottom.IsNaN())
{
- childPos = childPos.WithY(node.BelowNode.Position.Y + node.BelowNode.Element.DesiredSize.Height);
+ availableHeight -= node.Bottom;
}
+ }
+
+ var availableWidth = AvailableSize.Width - node.Left - node.Right;
+ if (availableWidth.IsNaN())
+ {
+ availableWidth = AvailableSize.Width;
- if (node.AlignHorizontalCenterWith != null)
+ if (!node.Left.IsNaN() && node.Right.IsNaN())
{
- childPos = childPos.WithX(node.AlignHorizontalCenterWith.Position.X +
- (node.AlignHorizontalCenterWith.Element.DesiredSize.Width - childSize.Width) / 2);
+ availableWidth -= node.Left;
}
-
- if (node.AlignVerticalCenterWith != null)
+ else if (node.Left.IsNaN() && !node.Right.IsNaN())
{
- childPos = childPos.WithY(node.AlignVerticalCenterWith.Position.Y +
- (node.AlignVerticalCenterWith.Element.DesiredSize.Height - childSize.Height) / 2);
+ availableWidth -= node.Right;
}
+ }
+
+ child.Measure(new Size(Math.Max(availableWidth, 0), Math.Max(availableHeight, 0)));
+ var childSize = child.DesiredSize;
+
+ if (node.LeftOfNode != null && node.Left.IsNaN())
+ {
+ node.Left = node.LeftOfNode.Left - childSize.Width;
+ }
+
+ if (node.AboveNode != null && node.Top.IsNaN())
+ {
+ node.Top = node.AboveNode.Top - childSize.Height;
+ }
- if (node.AlignLeftWithNode != null)
+ if (node.RightOfNode != null)
+ {
+ if (node.Right.IsNaN())
{
- childPos = childPos.WithX(node.AlignLeftWithNode.Position.X);
+ node.Right = node.RightOfNode.Right - childSize.Width;
}
- if (node.AlignTopWithNode != null)
+ if (node.Left.IsNaN())
{
- childPos = childPos.WithY(node.AlignTopWithNode.Position.Y);
+ node.Left = AvailableSize.Width - node.RightOfNode.Right;
}
+ }
- if (node.AlignRightWithNode != null)
+ if (node.BelowNode != null)
+ {
+ if (node.Bottom.IsNaN())
{
- childPos = childPos.WithX(node.AlignRightWithNode.Element.DesiredSize.Width + node.AlignRightWithNode.Position.X - childSize.Width);
+ node.Bottom = node.BelowNode.Bottom - childSize.Height;
}
- if (node.AlignBottomWithNode != null)
+ if (node.Top.IsNaN())
{
- childPos = childPos.WithY(node.AlignBottomWithNode.Element.DesiredSize.Height + node.AlignBottomWithNode.Position.Y - childSize.Height);
+ node.Top = AvailableSize.Height - node.BelowNode.Bottom;
}
}
- if (alignLeftWithPanel)
+ if (node.AlignHorizontalCenterWith != null)
{
- if (node.AlignRightWithNode != null)
- {
- childPos = childPos.WithX((node.AlignRightWithNode.Element.DesiredSize.Width + node.AlignRightWithNode.Position.X - childSize.Width) / 2);
- }
+ var halfWidthLeft = (AvailableSize.Width + node.AlignHorizontalCenterWith.Left - node.AlignHorizontalCenterWith.Right - childSize.Width) * 0.5;
+ var halfWidthRight = (AvailableSize.Width - node.AlignHorizontalCenterWith.Left + node.AlignHorizontalCenterWith.Right - childSize.Width) * 0.5;
+
+ if (node.Left.IsNaN())
+ node.Left = halfWidthLeft;
else
- {
- childPos = childPos.WithX(0);
- }
+ node.Left = (node.Left + halfWidthLeft) * 0.5;
+
+ if (node.Right.IsNaN())
+ node.Right = halfWidthRight;
+ else
+ node.Right = (node.Right + halfWidthRight) * 0.5;
}
- if (alignTopWithPanel)
+ if (node.AlignVerticalCenterWith != null)
{
- if (node.AlignBottomWithNode != null)
- {
- childPos = childPos.WithY((node.AlignBottomWithNode.Element.DesiredSize.Height + node.AlignBottomWithNode.Position.Y - childSize.Height) / 2);
- }
+ var halfHeightTop = (AvailableSize.Height + node.AlignVerticalCenterWith.Top - node.AlignVerticalCenterWith.Bottom - childSize.Height) * 0.5;
+ var halfHeightBottom = (AvailableSize.Height - node.AlignVerticalCenterWith.Top + node.AlignVerticalCenterWith.Bottom - childSize.Height) * 0.5;
+
+ if (node.Top.IsNaN())
+ node.Top = halfHeightTop;
else
- {
- childPos = childPos.WithY(0);
- }
+ node.Top = (node.Top + halfHeightTop) * 0.5;
+
+ if (node.Bottom.IsNaN())
+ node.Bottom = halfHeightBottom;
+ else
+ node.Bottom = (node.Bottom + halfHeightBottom) * 0.5;
}
- if (alignRightWithPanel)
+ if (GetAlignHorizontalCenterWithPanel(child))
{
- if (alignLeftWithPanel)
- {
- childPos = childPos.WithX((_arrangeSize.Width - childSize.Width) / 2);
- }
- else if (node.AlignLeftWithNode == null)
- {
- childPos = childPos.WithX(_arrangeSize.Width - childSize.Width);
- }
+ var halfSubWidth = (AvailableSize.Width - childSize.Width) * 0.5;
+
+ if (node.Left.IsNaN())
+ node.Left = halfSubWidth;
else
- {
- childPos = childPos.WithX((_arrangeSize.Width + node.AlignLeftWithNode.Position.X - childSize.Width) / 2);
- }
+ node.Left = (node.Left + halfSubWidth) * 0.5;
+
+ if (node.Right.IsNaN())
+ node.Right = halfSubWidth;
+ else
+ node.Right = (node.Right + halfSubWidth) * 0.5;
}
- if (alignBottomWithPanel)
+ if (GetAlignVerticalCenterWithPanel(child))
{
- if (alignTopWithPanel)
- {
- childPos = childPos.WithY((_arrangeSize.Height - childSize.Height) / 2);
- }
- else if (node.AlignTopWithNode == null)
+ var halfSubHeight = (AvailableSize.Height - childSize.Height) * 0.5;
+
+ if (node.Top.IsNaN())
+ node.Top = halfSubHeight;
+ else
+ node.Top = (node.Top + halfSubHeight) * 0.5;
+
+ if (node.Bottom.IsNaN())
+ node.Bottom = halfSubHeight;
+ else
+ node.Bottom = (node.Bottom + halfSubHeight) * 0.5;
+ }
+
+ if (node.Left.IsNaN())
+ {
+ if (!node.Right.IsNaN())
+ node.Left = AvailableSize.Width - node.Right - childSize.Width;
+ else
{
- childPos = childPos.WithY(_arrangeSize.Height - childSize.Height);
+ node.Left = 0;
+ node.Right = AvailableSize.Width - childSize.Width;
}
+ }
+ else if (!node.Left.IsNaN() && node.Right.IsNaN())
+ {
+ node.Right = AvailableSize.Width - node.Left - childSize.Width;
+ }
+
+ if (node.Top.IsNaN())
+ {
+ if (!node.Bottom.IsNaN())
+ node.Top = AvailableSize.Height - node.Bottom - childSize.Height;
else
{
- childPos = childPos.WithY((_arrangeSize.Height + node.AlignTopWithNode.Position.Y - childSize.Height) / 2);
+ node.Top = 0;
+ node.Bottom = AvailableSize.Height - childSize.Height;
}
}
+ else if (!node.Top.IsNaN() && node.Bottom.IsNaN())
+ {
+ node.Bottom = AvailableSize.Height - node.Top - childSize.Height;
+ }
+
+ node.Measured = true;
+ }
+
+ public Size GetBoundingSize(bool calcWidth, bool calcHeight)
+ {
+ var boundingSize = new Size();
+
+ foreach (var node in _nodeDic.Values)
+ {
+ var size = node.GetBoundingSize();
+ boundingSize = boundingSize.WithWidth(Math.Max(boundingSize.Width, size.Width));
+ boundingSize = boundingSize.WithHeight(Math.Max(boundingSize.Height, size.Height));
+ }
- child.Arrange(new Rect(childPos.X, childPos.Y, childSize.Width, childSize.Height));
- node.Position = childPos;
- node.Arranged = true;
+ boundingSize = boundingSize.WithWidth(calcWidth ? boundingSize.Width : AvailableSize.Width);
+ boundingSize = boundingSize.WithHeight(calcHeight ? boundingSize.Height : AvailableSize.Height);
+ return boundingSize;
}
}
}
+
+ internal static partial class Extensions
+ {
+ ///
+ /// Returns a value that indicates whether the specified value is not a number ().
+ ///
+ /// A double-precision floating-point number.
+ /// true if evaluates to ; otherwise, false.
+ public static bool IsNaN(this double d)
+ {
+ return double.IsNaN(d);
+ }
+
+ public static IEnumerable Do(this IEnumerable source, Action predicate)
+ {
+ var enumerable = source as IList ?? source.ToList();
+ foreach (var item in enumerable)
+ {
+ predicate.Invoke(item);
+ }
+
+ return enumerable;
+ }
+ }
}
diff --git a/src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs b/src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs
index f5c673d5f9..931c27c575 100644
--- a/src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs
+++ b/src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs
@@ -192,7 +192,7 @@ namespace Avalonia.Controls.Remote.Server
GetAvaloniaInputModifiers(pressed.Modifiers)));
}, DispatcherPriority.Input);
}
- if (obj is PointerPressedEventMessage released)
+ if (obj is PointerReleasedEventMessage released)
{
Dispatcher.UIThread.Post(() =>
{
diff --git a/src/Avalonia.Themes.Default/ToggleSwitch.xaml b/src/Avalonia.Themes.Default/ToggleSwitch.xaml
index 893d64f505..ded121f5f6 100644
--- a/src/Avalonia.Themes.Default/ToggleSwitch.xaml
+++ b/src/Avalonia.Themes.Default/ToggleSwitch.xaml
@@ -43,7 +43,8 @@
-
+
+
diff --git a/src/Avalonia.Themes.Fluent/ToggleSwitch.xaml b/src/Avalonia.Themes.Fluent/ToggleSwitch.xaml
index e7f8fb1641..4309edefe3 100644
--- a/src/Avalonia.Themes.Fluent/ToggleSwitch.xaml
+++ b/src/Avalonia.Themes.Fluent/ToggleSwitch.xaml
@@ -43,7 +43,8 @@
-
+
+
diff --git a/src/Markup/Avalonia.Markup/Data/BindingBase.cs b/src/Markup/Avalonia.Markup/Data/BindingBase.cs
index 7c4e7b5efe..3dbc83a7df 100644
--- a/src/Markup/Avalonia.Markup/Data/BindingBase.cs
+++ b/src/Markup/Avalonia.Markup/Data/BindingBase.cs
@@ -137,9 +137,9 @@ namespace Avalonia.Data
{
Contract.Requires(target != null);
- if (!(target is IStyledElement))
+ if (!(target is IDataContextProvider))
{
- target = anchor as IStyledElement;
+ target = anchor as IDataContextProvider;
if (target == null)
{
diff --git a/tests/Avalonia.Controls.UnitTests/ApplicationTests.cs b/tests/Avalonia.Controls.UnitTests/ApplicationTests.cs
index e533001242..58ddc8ca60 100644
--- a/tests/Avalonia.Controls.UnitTests/ApplicationTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/ApplicationTests.cs
@@ -1,6 +1,5 @@
using System;
-using System.Collections.Generic;
-using Avalonia.Threading;
+using Avalonia.Data;
using Avalonia.UnitTests;
using Xunit;
@@ -32,5 +31,20 @@ namespace Avalonia.Controls.UnitTests
Assert.True(raised);
}
}
+
+ [Fact]
+ public void Can_Bind_To_DataContext()
+ {
+ using (UnitTestApplication.Start())
+ {
+ var application = Application.Current;
+
+ application.DataContext = "Test";
+
+ application.Bind(Application.NameProperty, new Binding("."));
+
+ Assert.Equal("Test", Application.Current.Name);
+ }
+ }
}
}
diff --git a/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests.cs b/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests.cs
index fddc02f19c..fab57cec49 100644
--- a/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests.cs
@@ -60,6 +60,25 @@ namespace Avalonia.Controls.UnitTests.Presenters
Assert.IsType(target.Panel.Children[1]);
}
+ [Fact]
+ public void Should_Create_Containers_Only_Once()
+ {
+ var parent = new TestItemsControl();
+ var target = new ItemsPresenter
+ {
+ Items = new[] { "foo", "bar" },
+ [StyledElement.TemplatedParentProperty] = parent,
+ };
+ var raised = 0;
+
+ parent.ItemContainerGenerator.Materialized += (s, e) => ++raised;
+
+ target.ApplyTemplate();
+
+ Assert.Equal(2, target.Panel.Children.Count);
+ Assert.Equal(2, raised);
+ }
+
[Fact]
public void ItemContainerGenerator_Should_Be_Picked_Up_From_TemplatedControl()
{
diff --git a/tests/Avalonia.Controls.UnitTests/RelativePanelTests.cs b/tests/Avalonia.Controls.UnitTests/RelativePanelTests.cs
index 4248e643eb..7b1f6d07b7 100644
--- a/tests/Avalonia.Controls.UnitTests/RelativePanelTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/RelativePanelTests.cs
@@ -31,6 +31,7 @@ namespace Avalonia.Controls.UnitTests
Assert.Equal(new Rect(20, 0, 20, 20), target.Children[1].Bounds);
}
+ [Fact]
public void Lays_Out_1_Child_Below_the_other()
{
var rect1 = new Rectangle { Height = 20, Width = 20 };
@@ -55,5 +56,31 @@ namespace Avalonia.Controls.UnitTests
Assert.Equal(new Rect(0, 0, 20, 20), target.Children[0].Bounds);
Assert.Equal(new Rect(0, 20, 20, 20), target.Children[1].Bounds);
}
+
+ [Fact]
+ public void RelativePanel_Can_Center()
+ {
+ var rect1 = new Rectangle { Height = 20, Width = 20 };
+ var rect2 = new Rectangle { Height = 20, Width = 20 };
+
+ var target = new RelativePanel
+ {
+ VerticalAlignment = Layout.VerticalAlignment.Center,
+ HorizontalAlignment = Layout.HorizontalAlignment.Center,
+ Children =
+ {
+ rect1, rect2
+ }
+ };
+
+ RelativePanel.SetAlignLeftWithPanel(rect1, true);
+ RelativePanel.SetBelow(rect2, rect1);
+ target.Measure(new Size(400, 400));
+ target.Arrange(new Rect(target.DesiredSize));
+
+ Assert.Equal(new Size(20, 40), target.Bounds.Size);
+ Assert.Equal(new Rect(0, 0, 20, 20), target.Children[0].Bounds);
+ Assert.Equal(new Rect(0, 20, 20, 20), target.Children[1].Bounds);
+ }
}
}