Browse Source

Merge branch 'master' into win32-sync-context-fix

pull/4242/head
Dariusz Komosiński 6 years ago
committed by GitHub
parent
commit
9ab167f6f2
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      src/Avalonia.Controls/Presenters/CarouselPresenter.cs
  2. 2
      src/Avalonia.Controls/Presenters/ItemsPresenterBase.cs
  3. 2
      src/Avalonia.Controls/RelativePanel.AttachedProperties.cs
  4. 485
      src/Avalonia.Controls/RelativePanel.cs
  5. 2
      src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs
  6. 3
      src/Avalonia.Themes.Default/ToggleSwitch.xaml
  7. 3
      src/Avalonia.Themes.Fluent/ToggleSwitch.xaml
  8. 4
      src/Markup/Avalonia.Markup/Data/BindingBase.cs
  9. 18
      tests/Avalonia.Controls.UnitTests/ApplicationTests.cs
  10. 19
      tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests.cs
  11. 27
      tests/Avalonia.Controls.UnitTests/RelativePanelTests.cs

5
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));
}
/// <summary>
/// Moves to the selected page, animating if a <see cref="PageTransition"/> is set.
/// </summary>

2
src/Avalonia.Controls/Presenters/ItemsPresenterBase.cs

@ -229,8 +229,6 @@ namespace Avalonia.Controls.Presenters
}
PanelCreated(Panel);
ItemsChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
/// <summary>

2
src/Avalonia.Controls/RelativePanel.AttachedProperties.cs

@ -33,7 +33,7 @@ namespace Avalonia.Controls
AlignVerticalCenterWithProperty.Changed.AddClassHandler<Layoutable>(OnAlignPropertiesChanged);
BelowProperty.Changed.AddClassHandler<Layoutable>(OnAlignPropertiesChanged);
LeftOfProperty.Changed.AddClassHandler<Layoutable>(OnAlignPropertiesChanged);
LeftOfProperty.Changed.AddClassHandler<Layoutable>(OnAlignPropertiesChanged);
RightOfProperty.Changed.AddClassHandler<Layoutable>(OnAlignPropertiesChanged);
}
/// <summary>

485
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<Layoutable>())
_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<GraphNode> OutgoingNodes { get; }
@ -132,19 +116,101 @@ namespace Avalonia.Controls
OutgoingNodes = new HashSet<GraphNode>();
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<GraphNode> 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<AvaloniaObject, GraphNode> _nodeDic;
private Size _arrangeSize;
private Size AvailableSize { get; set; }
public Graph()
public Graph() => _nodeDic = new Dictionary<AvaloniaObject, GraphNode>();
public IEnumerable<GraphNode> GetNodes() => _nodeDic.Values;
public void Clear()
{
_nodeDic = new Dictionary<AvaloniaObject, GraphNode>();
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<GraphNode> nodes, HashSet<Layoutable>? set)
private void Measure(IEnumerable<GraphNode> nodes, HashSet<AvaloniaObject>? set)
{
set ??= new HashSet<Layoutable>();
set ??= new HashSet<AvaloniaObject>();
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
{
/// <summary>
/// Returns a value that indicates whether the specified value is not a number ().
/// </summary>
/// <param name="d">A double-precision floating-point number.</param>
/// <returns>true if evaluates to ; otherwise, false.</returns>
public static bool IsNaN(this double d)
{
return double.IsNaN(d);
}
public static IEnumerable<TSource> Do<TSource>(this IEnumerable<TSource> source, Action<TSource> predicate)
{
var enumerable = source as IList<TSource> ?? source.ToList();
foreach (var item in enumerable)
{
predicate.Invoke(item);
}
return enumerable;
}
}
}

2
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(() =>
{

3
src/Avalonia.Themes.Default/ToggleSwitch.xaml

@ -43,7 +43,8 @@
<Setter Property="Foreground" Value="{DynamicResource ToggleSwitchContentForeground}" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="FontSize" Value="{DynamicResource ControlContentThemeFontSize}" />
<Setter Property="Template">
<ControlTemplate>

3
src/Avalonia.Themes.Fluent/ToggleSwitch.xaml

@ -43,7 +43,8 @@
<Setter Property="Foreground" Value="{DynamicResource ToggleSwitchContentForeground}" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="FontSize" Value="{DynamicResource ControlContentThemeFontSize}" />
<Setter Property="Template">
<ControlTemplate>

4
src/Markup/Avalonia.Markup/Data/BindingBase.cs

@ -137,9 +137,9 @@ namespace Avalonia.Data
{
Contract.Requires<ArgumentNullException>(target != null);
if (!(target is IStyledElement))
if (!(target is IDataContextProvider))
{
target = anchor as IStyledElement;
target = anchor as IDataContextProvider;
if (target == null)
{

18
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);
}
}
}
}

19
tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests.cs

@ -60,6 +60,25 @@ namespace Avalonia.Controls.UnitTests.Presenters
Assert.IsType<ListBoxItem>(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()
{

27
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);
}
}
}

Loading…
Cancel
Save