diff --git a/src/Avalonia.Controls/Border.cs b/src/Avalonia.Controls/Border.cs
index 8acb3603c9..0382c8d675 100644
--- a/src/Avalonia.Controls/Border.cs
+++ b/src/Avalonia.Controls/Border.cs
@@ -3,6 +3,7 @@
using Avalonia;
using Avalonia.Controls.Utils;
+using Avalonia.Layout;
using Avalonia.Media;
namespace Avalonia.Controls
@@ -99,7 +100,7 @@ namespace Avalonia.Controls
/// The desired size of the control.
protected override Size MeasureOverride(Size availableSize)
{
- return MeasureOverrideImpl(availableSize, Child, Padding, BorderThickness);
+ return LayoutHelper.MeasureChild(Child, availableSize, Padding, BorderThickness);
}
///
@@ -109,32 +110,9 @@ namespace Avalonia.Controls
/// The space taken.
protected override Size ArrangeOverride(Size finalSize)
{
- if (Child != null)
- {
- var padding = Padding + BorderThickness;
- Child.Arrange(new Rect(finalSize).Deflate(padding));
- }
-
_borderRenderHelper.Update(finalSize, BorderThickness, CornerRadius);
- return finalSize;
- }
-
- internal static Size MeasureOverrideImpl(
- Size availableSize,
- IControl child,
- Thickness padding,
- Thickness borderThickness)
- {
- padding += borderThickness;
-
- if (child != null)
- {
- child.Measure(availableSize.Deflate(padding));
- return child.DesiredSize.Inflate(padding);
- }
-
- return new Size(padding.Left + padding.Right, padding.Bottom + padding.Top);
+ return LayoutHelper.ArrangeChild(Child, finalSize, Padding, BorderThickness);
}
}
}
\ No newline at end of file
diff --git a/src/Avalonia.Controls/Decorator.cs b/src/Avalonia.Controls/Decorator.cs
index 4040e4b8b7..389cf66d34 100644
--- a/src/Avalonia.Controls/Decorator.cs
+++ b/src/Avalonia.Controls/Decorator.cs
@@ -1,6 +1,7 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
+using Avalonia.Layout;
using Avalonia.Metadata;
namespace Avalonia.Controls
@@ -53,25 +54,13 @@ namespace Avalonia.Controls
///
protected override Size MeasureOverride(Size availableSize)
{
- var content = Child;
- var padding = Padding;
-
- if (content != null)
- {
- content.Measure(availableSize.Deflate(padding));
- return content.DesiredSize.Inflate(padding);
- }
- else
- {
- return new Size(padding.Left + padding.Right, padding.Bottom + padding.Top);
- }
+ return LayoutHelper.MeasureChild(Child, availableSize, Padding);
}
///
protected override Size ArrangeOverride(Size finalSize)
{
- Child?.Arrange(new Rect(finalSize).Deflate(Padding));
- return finalSize;
+ return LayoutHelper.ArrangeChild(Child, finalSize, Padding);
}
///
diff --git a/src/Avalonia.Controls/Platform/IWindowImpl.cs b/src/Avalonia.Controls/Platform/IWindowImpl.cs
index 3f2c977718..f1f3925133 100644
--- a/src/Avalonia.Controls/Platform/IWindowImpl.cs
+++ b/src/Avalonia.Controls/Platform/IWindowImpl.cs
@@ -16,6 +16,11 @@ namespace Avalonia.Platform
///
WindowState WindowState { get; set; }
+ ///
+ /// Gets or sets a method called when the minimized/maximized state of the window changes.
+ ///
+ Action WindowStateChanged { get; set; }
+
///
/// Sets the title of the window.
///
diff --git a/src/Avalonia.Controls/Presenters/ContentPresenter.cs b/src/Avalonia.Controls/Presenters/ContentPresenter.cs
index 3cc750e20d..6badf91367 100644
--- a/src/Avalonia.Controls/Presenters/ContentPresenter.cs
+++ b/src/Avalonia.Controls/Presenters/ContentPresenter.cs
@@ -35,6 +35,13 @@ namespace Avalonia.Controls.Presenters
public static readonly StyledProperty BorderThicknessProperty =
Border.BorderThicknessProperty.AddOwner();
+ ///
+ /// Defines the property.
+ ///
+ public static readonly StyledProperty CornerRadiusProperty =
+ Border.CornerRadiusProperty.AddOwner();
+
+
///
/// Defines the property.
///
@@ -55,12 +62,6 @@ namespace Avalonia.Controls.Presenters
public static readonly StyledProperty ContentTemplateProperty =
ContentControl.ContentTemplateProperty.AddOwner();
- ///
- /// Defines the property.
- ///
- public static readonly StyledProperty CornerRadiusProperty =
- Border.CornerRadiusProperty.AddOwner();
-
///
/// Defines the property.
///
@@ -90,19 +91,12 @@ namespace Avalonia.Controls.Presenters
static ContentPresenter()
{
AffectsRender(BackgroundProperty, BorderBrushProperty, BorderThicknessProperty, CornerRadiusProperty);
- AffectsMeasure(BorderThicknessProperty);
+ AffectsMeasure(BorderThicknessProperty, PaddingProperty);
ContentProperty.Changed.AddClassHandler(x => x.ContentChanged);
ContentTemplateProperty.Changed.AddClassHandler(x => x.ContentChanged);
TemplatedParentProperty.Changed.AddClassHandler(x => x.TemplatedParentChanged);
}
- ///
- /// Initializes a new instance of the class.
- ///
- public ContentPresenter()
- {
- }
-
///
/// Gets or sets a brush with which to paint the background.
///
@@ -130,6 +124,15 @@ namespace Avalonia.Controls.Presenters
set { SetValue(BorderThicknessProperty, value); }
}
+ ///
+ /// Gets or sets the radius of the border rounded corners.
+ ///
+ public CornerRadius CornerRadius
+ {
+ get { return GetValue(CornerRadiusProperty); }
+ set { SetValue(CornerRadiusProperty, value); }
+ }
+
///
/// Gets the control displayed by the presenter.
///
@@ -159,16 +162,7 @@ namespace Avalonia.Controls.Presenters
}
///
- /// Gets or sets the radius of the border rounded corners.
- ///
- public CornerRadius CornerRadius
- {
- get { return GetValue(CornerRadiusProperty); }
- set { SetValue(CornerRadiusProperty, value); }
- }
-
- ///
- /// Gets or sets the horizontal alignment of the content within the control.
+ /// Gets or sets the horizontal alignment of the content within the border the control.
///
public HorizontalAlignment HorizontalContentAlignment
{
@@ -177,7 +171,7 @@ namespace Avalonia.Controls.Presenters
}
///
- /// Gets or sets the vertical alignment of the content within the control.
+ /// Gets or sets the vertical alignment of the content within the border of the control.
///
public VerticalAlignment VerticalContentAlignment
{
@@ -186,7 +180,7 @@ namespace Avalonia.Controls.Presenters
}
///
- /// Gets or sets the padding to place around the control.
+ /// Gets or sets the space between the border and the control.
///
public Thickness Padding
{
@@ -195,7 +189,7 @@ namespace Avalonia.Controls.Presenters
}
///
- public override sealed void ApplyTemplate()
+ public sealed override void ApplyTemplate()
{
if (!_createdChild && ((ILogical)this).IsAttachedToLogicalTree)
{
@@ -328,96 +322,68 @@ namespace Avalonia.Controls.Presenters
///
protected override Size MeasureOverride(Size availableSize)
{
- return Border.MeasureOverrideImpl(availableSize, Child, Padding, BorderThickness);
+ return LayoutHelper.MeasureChild(Child, availableSize, Padding, BorderThickness);
}
///
protected override Size ArrangeOverride(Size finalSize)
{
- finalSize = ArrangeOverrideImpl(finalSize, new Vector());
-
_borderRenderer.Update(finalSize, BorderThickness, CornerRadius);
- return finalSize;
- }
-
- ///
- /// Called when the property changes.
- ///
- /// The event args.
- private void ContentChanged(AvaloniaPropertyChangedEventArgs e)
- {
- _createdChild = false;
-
- if (((ILogical)this).IsAttachedToLogicalTree)
- {
- UpdateChild();
- }
- else if (Child != null)
- {
- VisualChildren.Remove(Child);
- LogicalChildren.Remove(Child);
- Child = null;
- _dataTemplate = null;
- }
-
- InvalidateMeasure();
+ return ArrangeOverrideImpl(finalSize, new Vector());
}
internal Size ArrangeOverrideImpl(Size finalSize, Vector offset)
{
if (Child == null) return finalSize;
- var padding = Padding;
- var borderThickness = BorderThickness;
+ var padding = Padding + BorderThickness;
var horizontalContentAlignment = HorizontalContentAlignment;
var verticalContentAlignment = VerticalContentAlignment;
var useLayoutRounding = UseLayoutRounding;
- var availableSizeMinusMargins = new Size(
- Math.Max(0, finalSize.Width - padding.Left - padding.Right - borderThickness.Left - borderThickness.Right),
- Math.Max(0, finalSize.Height - padding.Top - padding.Bottom - borderThickness.Top - borderThickness.Bottom));
- var size = availableSizeMinusMargins;
+ var availableSize = finalSize;
+ var sizeForChild = availableSize;
var scale = GetLayoutScale();
- var originX = offset.X + padding.Left + borderThickness.Left;
- var originY = offset.Y + padding.Top + borderThickness.Top;
+ var originX = offset.X;
+ var originY = offset.Y;
if (horizontalContentAlignment != HorizontalAlignment.Stretch)
{
- size = size.WithWidth(Math.Min(size.Width, DesiredSize.Width - padding.Left - padding.Right));
+ sizeForChild = sizeForChild.WithWidth(Math.Min(sizeForChild.Width, DesiredSize.Width));
}
if (verticalContentAlignment != VerticalAlignment.Stretch)
{
- size = size.WithHeight(Math.Min(size.Height, DesiredSize.Height - padding.Top - padding.Bottom));
+ sizeForChild = sizeForChild.WithHeight(Math.Min(sizeForChild.Height, DesiredSize.Height));
}
if (useLayoutRounding)
{
- size = new Size(
- Math.Ceiling(size.Width * scale) / scale,
- Math.Ceiling(size.Height * scale) / scale);
- availableSizeMinusMargins = new Size(
- Math.Ceiling(availableSizeMinusMargins.Width * scale) / scale,
- Math.Ceiling(availableSizeMinusMargins.Height * scale) / scale);
+ sizeForChild = new Size(
+ Math.Ceiling(sizeForChild.Width * scale) / scale,
+ Math.Ceiling(sizeForChild.Height * scale) / scale);
+ availableSize = new Size(
+ Math.Ceiling(availableSize.Width * scale) / scale,
+ Math.Ceiling(availableSize.Height * scale) / scale);
}
switch (horizontalContentAlignment)
{
case HorizontalAlignment.Center:
- originX += (availableSizeMinusMargins.Width - size.Width) / 2;
+ originX += (availableSize.Width - sizeForChild.Width) / 2;
break;
case HorizontalAlignment.Right:
- originX += availableSizeMinusMargins.Width - size.Width;
+ originX += availableSize.Width - sizeForChild.Width;
break;
}
switch (verticalContentAlignment)
{
case VerticalAlignment.Center:
- originY += (availableSizeMinusMargins.Height - size.Height) / 2;
+ originY += (availableSize.Height - sizeForChild.Height) / 2;
break;
case VerticalAlignment.Bottom:
- originY += availableSizeMinusMargins.Height - size.Height;
+ originY += availableSize.Height - sizeForChild.Height;
break;
}
@@ -427,11 +393,37 @@ namespace Avalonia.Controls.Presenters
originY = Math.Floor(originY * scale) / scale;
}
- Child.Arrange(new Rect(originX, originY, Math.Max(0, size.Width), Math.Max(0, size.Height)));
+ var boundsForChild =
+ new Rect(originX, originY, sizeForChild.Width, sizeForChild.Height).Deflate(padding);
+
+ Child.Arrange(boundsForChild);
return finalSize;
}
+ ///
+ /// Called when the property changes.
+ ///
+ /// The event args.
+ private void ContentChanged(AvaloniaPropertyChangedEventArgs e)
+ {
+ _createdChild = false;
+
+ if (((ILogical)this).IsAttachedToLogicalTree)
+ {
+ UpdateChild();
+ }
+ else if (Child != null)
+ {
+ VisualChildren.Remove(Child);
+ LogicalChildren.Remove(Child);
+ Child = null;
+ _dataTemplate = null;
+ }
+
+ InvalidateMeasure();
+ }
+
private double GetLayoutScale()
{
var result = (VisualRoot as ILayoutRoot)?.LayoutScaling ?? 1.0;
diff --git a/src/Avalonia.Controls/Utils/BorderRenderHelper.cs b/src/Avalonia.Controls/Utils/BorderRenderHelper.cs
index d9169e51f3..0fd6593fbe 100644
--- a/src/Avalonia.Controls/Utils/BorderRenderHelper.cs
+++ b/src/Avalonia.Controls/Utils/BorderRenderHelper.cs
@@ -26,17 +26,17 @@ namespace Avalonia.Controls.Utils
var boundRect = new Rect(finalSize);
var innerRect = boundRect.Deflate(borderThickness);
- var innerCoordinates = new BorderCoordinates(cornerRadius, borderThickness, false);
-
+ BorderGeometryKeypoints backgroundKeypoints = null;
StreamGeometry backgroundGeometry = null;
if (innerRect.Width != 0 && innerRect.Height != 0)
{
backgroundGeometry = new StreamGeometry();
+ backgroundKeypoints = new BorderGeometryKeypoints(innerRect, borderThickness, cornerRadius, true);
using (var ctx = backgroundGeometry.Open())
{
- CreateGeometry(ctx, innerRect, innerCoordinates);
+ CreateGeometry(ctx, innerRect, backgroundKeypoints);
}
_backgroundGeometryCache = backgroundGeometry;
@@ -48,16 +48,16 @@ namespace Avalonia.Controls.Utils
if (boundRect.Width != 0 && innerRect.Height != 0)
{
- var outerCoordinates = new BorderCoordinates(cornerRadius, borderThickness, true);
+ var borderGeometryKeypoints = new BorderGeometryKeypoints(boundRect, borderThickness, cornerRadius, false);
var borderGeometry = new StreamGeometry();
using (var ctx = borderGeometry.Open())
{
- CreateGeometry(ctx, boundRect, outerCoordinates);
+ CreateGeometry(ctx, boundRect, borderGeometryKeypoints);
if (backgroundGeometry != null)
{
- CreateGeometry(ctx, innerRect, innerCoordinates);
+ CreateGeometry(ctx, innerRect, backgroundKeypoints);
}
}
@@ -104,176 +104,156 @@ namespace Avalonia.Controls.Utils
}
}
- private static void CreateGeometry(StreamGeometryContext context, Rect boundRect, BorderCoordinates borderCoordinates)
- {
- var topLeft = new Point(borderCoordinates.LeftTop, 0);
- var topRight = new Point(boundRect.Width - borderCoordinates.RightTop, 0);
- var rightTop = new Point(boundRect.Width, borderCoordinates.TopRight);
- var rightBottom = new Point(boundRect.Width, boundRect.Height - borderCoordinates.BottomRight);
- var bottomRight = new Point(boundRect.Width - borderCoordinates.RightBottom, boundRect.Height);
- var bottomLeft = new Point(borderCoordinates.LeftBottom, boundRect.Height);
- var leftBottom = new Point(0, boundRect.Height - borderCoordinates.BottomLeft);
- var leftTop = new Point(0, borderCoordinates.TopLeft);
+ private class BorderGeometryKeypoints
+ {
+ internal BorderGeometryKeypoints(Rect boundRect, Thickness borderThickness, CornerRadius cornerRadius, bool inner)
+ {
+ var left = 0.5 * borderThickness.Left;
+ var top = 0.5 * borderThickness.Top;
+ var right = 0.5 * borderThickness.Right;
+ var bottom = 0.5 * borderThickness.Bottom;
+ double leftTopY;
+ double topLeftX;
+ double topRightX;
+ double rightTopY;
+ double rightBottomY;
+ double bottomRightX;
+ double bottomLeftX;
+ double leftBottomY;
- if (topLeft.X > topRight.X)
- {
- var scaledX = borderCoordinates.LeftTop / (borderCoordinates.LeftTop + borderCoordinates.RightTop) * boundRect.Width;
- topLeft = new Point(scaledX, topLeft.Y);
- topRight = new Point(scaledX, topRight.Y);
- }
+ if (inner)
+ {
+ leftTopY = Math.Max(0, cornerRadius.TopLeft - top) + boundRect.TopLeft.Y;
+ topLeftX = Math.Max(0, cornerRadius.TopLeft - left) + boundRect.TopLeft.X;
+ topRightX = boundRect.Width - Math.Max(0, cornerRadius.TopRight - top) + boundRect.TopLeft.X;
+ rightTopY = Math.Max(0, cornerRadius.TopRight - right) + boundRect.TopLeft.Y;
+ rightBottomY = boundRect.Height - Math.Max(0, cornerRadius.BottomRight - bottom) + boundRect.TopLeft.Y;
+ bottomRightX = boundRect.Width - Math.Max(0, cornerRadius.BottomRight - right) + boundRect.TopLeft.X;
+ bottomLeftX = Math.Max(0, cornerRadius.BottomLeft - left) + boundRect.TopLeft.X;
+ leftBottomY = boundRect.Height - Math.Max(0, cornerRadius.BottomLeft - bottom) + boundRect.TopLeft.Y;
+ }
+ else
+ {
+
+ leftTopY = cornerRadius.TopLeft + top + boundRect.TopLeft.Y;
+ topLeftX = cornerRadius.TopLeft + left + boundRect.TopLeft.X;
+ topRightX = boundRect.Width - (cornerRadius.TopRight + right) + boundRect.TopLeft.X;
+ rightTopY = cornerRadius.TopRight + top + boundRect.TopLeft.Y;
+ rightBottomY = boundRect.Height - (cornerRadius.BottomRight + bottom) + boundRect.TopLeft.Y;
+ bottomRightX = boundRect.Width - (cornerRadius.BottomRight + right) + boundRect.TopLeft.X;
+ bottomLeftX = cornerRadius.BottomLeft + left + boundRect.TopLeft.X;
+ leftBottomY = boundRect.Height - (cornerRadius.BottomLeft + bottom) + boundRect.TopLeft.Y;
+ }
+
+ var leftTopX = boundRect.TopLeft.X;
+ var topLeftY = boundRect.TopLeft.Y;
+ var topRightY = boundRect.TopLeft.Y;
+ var rightTopX = boundRect.Width + boundRect.TopLeft.X;
+ var rightBottomX = boundRect.Width + boundRect.TopLeft.X;
+ var bottomRightY = boundRect.Height + boundRect.TopLeft.Y;
+ var bottomLeftY = boundRect.Height + boundRect.TopLeft.Y;
+ var leftBottomX = boundRect.TopLeft.X;
+
+ LeftTop = new Point(leftTopX, leftTopY);
+ TopLeft = new Point(topLeftX, topLeftY);
+ TopRight = new Point(topRightX, topRightY);
+ RightTop = new Point(rightTopX, rightTopY);
+ RightBottom = new Point(rightBottomX, rightBottomY);
+ BottomRight = new Point(bottomRightX, bottomRightY);
+ BottomLeft = new Point(bottomLeftX, bottomLeftY);
+ LeftBottom = new Point(leftBottomX, leftBottomY);
+
+ //Fix overlap
+ if (TopLeft.X > TopRight.X)
+ {
+ var scaledX = topLeftX / (topLeftX + topRightX) * boundRect.Width;
+ TopLeft = new Point(scaledX, TopLeft.Y);
+ TopRight = new Point(scaledX, TopRight.Y);
+ }
- if (rightTop.Y > rightBottom.Y)
- {
- var scaledY = borderCoordinates.TopRight / (borderCoordinates.TopRight + borderCoordinates.BottomRight) * boundRect.Height;
- rightTop = new Point(rightTop.X, scaledY);
- rightBottom = new Point(rightBottom.X, scaledY);
- }
+ if (RightTop.Y > RightBottom.Y)
+ {
+ var scaledY = rightBottomY / (rightTopY + rightBottomY) * boundRect.Height;
+ RightTop = new Point(RightTop.X, scaledY);
+ RightBottom = new Point(RightBottom.X, scaledY);
+ }
- if (bottomRight.X < bottomLeft.X)
- {
- var scaledX = borderCoordinates.LeftBottom / (borderCoordinates.LeftBottom + borderCoordinates.RightBottom) * boundRect.Width;
- bottomRight = new Point(scaledX, bottomRight.Y);
- bottomLeft = new Point(scaledX, bottomLeft.Y);
- }
+ if (BottomRight.X < BottomLeft.X)
+ {
+ var scaledX = bottomLeftX / (bottomLeftX + bottomRightX) * boundRect.Width;
+ BottomRight = new Point(scaledX, BottomRight.Y);
+ BottomLeft = new Point(scaledX, BottomLeft.Y);
+ }
- if (leftBottom.Y < leftTop.Y)
- {
- var scaledY = borderCoordinates.TopLeft / (borderCoordinates.TopLeft + borderCoordinates.BottomLeft) * boundRect.Height;
- leftBottom = new Point(leftBottom.X, scaledY);
- leftTop = new Point(leftTop.X, scaledY);
+ if (LeftBottom.Y < LeftTop.Y)
+ {
+ var scaledY = leftTopY / (leftTopY + leftBottomY) * boundRect.Height;
+ LeftBottom = new Point(LeftBottom.X, scaledY);
+ LeftTop = new Point(LeftTop.X, scaledY);
+ }
}
- var offset = new Vector(boundRect.TopLeft.X, boundRect.TopLeft.Y);
- topLeft += offset;
- topRight += offset;
- rightTop += offset;
- rightBottom += offset;
- bottomRight += offset;
- bottomLeft += offset;
- leftBottom += offset;
- leftTop += offset;
+ internal Point LeftTop { get; private set; }
+ internal Point TopLeft { get; private set; }
+ internal Point TopRight { get; private set; }
+ internal Point RightTop { get; private set; }
+ internal Point RightBottom { get; private set; }
+ internal Point BottomRight { get; private set; }
+ internal Point BottomLeft { get; private set; }
+ internal Point LeftBottom { get; private set; }
+ }
- context.BeginFigure(topLeft, true);
+ private static void CreateGeometry(StreamGeometryContext context, Rect boundRect, BorderGeometryKeypoints keypoints)
+ {
+ context.BeginFigure(keypoints.TopLeft, true);
//Top
- context.LineTo(topRight);
+ context.LineTo(keypoints.TopRight);
//TopRight corner
- var radiusX = boundRect.TopRight.X - topRight.X;
- var radiusY = rightTop.Y - boundRect.TopRight.Y;
+ var radiusX = boundRect.TopRight.X - keypoints.TopRight.X;
+ var radiusY = keypoints.RightTop.Y - boundRect.TopRight.Y;
if (radiusX != 0 || radiusY != 0)
{
- context.ArcTo(rightTop, new Size(radiusY, radiusY), 0, false, SweepDirection.Clockwise);
+ context.ArcTo(keypoints.RightTop, new Size(radiusY, radiusY), 0, false, SweepDirection.Clockwise);
}
//Right
- context.LineTo(rightBottom);
+ context.LineTo(keypoints.RightBottom);
//BottomRight corner
- radiusX = boundRect.BottomRight.X - bottomRight.X;
- radiusY = boundRect.BottomRight.Y - rightBottom.Y;
+ radiusX = boundRect.BottomRight.X - keypoints.BottomRight.X;
+ radiusY = boundRect.BottomRight.Y - keypoints.RightBottom.Y;
if (radiusX != 0 || radiusY != 0)
{
- context.ArcTo(bottomRight, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise);
+ context.ArcTo(keypoints.BottomRight, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise);
}
//Bottom
- context.LineTo(bottomLeft);
+ context.LineTo(keypoints.BottomLeft);
//BottomLeft corner
- radiusX = bottomLeft.X - boundRect.BottomLeft.X;
- radiusY = boundRect.BottomLeft.Y - leftBottom.Y;
+ radiusX = keypoints.BottomLeft.X - boundRect.BottomLeft.X;
+ radiusY = boundRect.BottomLeft.Y - keypoints.LeftBottom.Y;
if (radiusX != 0 || radiusY != 0)
{
- context.ArcTo(leftBottom, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise);
+ context.ArcTo(keypoints.LeftBottom, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise);
}
//Left
- context.LineTo(leftTop);
+ context.LineTo(keypoints.LeftTop);
//TopLeft corner
- radiusX = topLeft.X - boundRect.TopLeft.X;
- radiusY = leftTop.Y - boundRect.TopLeft.Y;
+ radiusX = keypoints.TopLeft.X - boundRect.TopLeft.X;
+ radiusY = keypoints.LeftTop.Y - boundRect.TopLeft.Y;
if (radiusX != 0 || radiusY != 0)
{
- context.ArcTo(topLeft, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise);
+ context.ArcTo(keypoints.TopLeft, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise);
}
context.EndFigure(true);
}
-
- private struct BorderCoordinates
- {
- internal BorderCoordinates(CornerRadius cornerRadius, Thickness borderThickness, bool isOuter)
- {
- var left = 0.5 * borderThickness.Left;
- var top = 0.5 * borderThickness.Top;
- var right = 0.5 * borderThickness.Right;
- var bottom = 0.5 * borderThickness.Bottom;
-
- if (isOuter)
- {
- if (cornerRadius.TopLeft == 0)
- {
- LeftTop = TopLeft = 0.0;
- }
- else
- {
- LeftTop = cornerRadius.TopLeft + left;
- TopLeft = cornerRadius.TopLeft + top;
- }
- if (cornerRadius.TopRight == 0)
- {
- TopRight = RightTop = 0;
- }
- else
- {
- TopRight = cornerRadius.TopRight + top;
- RightTop = cornerRadius.TopRight + right;
- }
- if (cornerRadius.BottomRight == 0)
- {
- RightBottom = BottomRight = 0;
- }
- else
- {
- RightBottom = cornerRadius.BottomRight + right;
- BottomRight = cornerRadius.BottomRight + bottom;
- }
- if (cornerRadius.BottomLeft == 0)
- {
- BottomLeft = LeftBottom = 0;
- }
- else
- {
- BottomLeft = cornerRadius.BottomLeft + bottom;
- LeftBottom = cornerRadius.BottomLeft + left;
- }
- }
- else
- {
- LeftTop = Math.Max(0, cornerRadius.TopLeft - left);
- TopLeft = Math.Max(0, cornerRadius.TopLeft - top);
- TopRight = Math.Max(0, cornerRadius.TopRight - top);
- RightTop = Math.Max(0, cornerRadius.TopRight - right);
- RightBottom = Math.Max(0, cornerRadius.BottomRight - right);
- BottomRight = Math.Max(0, cornerRadius.BottomRight - bottom);
- BottomLeft = Math.Max(0, cornerRadius.BottomLeft - bottom);
- LeftBottom = Math.Max(0, cornerRadius.BottomLeft - left);
- }
- }
-
- internal readonly double LeftTop;
- internal readonly double TopLeft;
- internal readonly double TopRight;
- internal readonly double RightTop;
- internal readonly double RightBottom;
- internal readonly double BottomRight;
- internal readonly double BottomLeft;
- internal readonly double LeftBottom;
- }
-
}
}
diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs
index 91d6c874d3..c4a09ac043 100644
--- a/src/Avalonia.Controls/Window.cs
+++ b/src/Avalonia.Controls/Window.cs
@@ -67,13 +67,19 @@ namespace Avalonia.Controls
///
public static readonly StyledProperty HasSystemDecorationsProperty =
AvaloniaProperty.Register(nameof(HasSystemDecorations), true);
-
+
///
/// Enables or disables the taskbar icon
///
public static readonly StyledProperty ShowInTaskbarProperty =
AvaloniaProperty.Register(nameof(ShowInTaskbar), true);
-
+
+ ///
+ /// Enables or disables the taskbar icon
+ ///
+ public static readonly StyledProperty WindowStateProperty =
+ AvaloniaProperty.Register(nameof(WindowState));
+
///
/// Defines the property.
///
@@ -118,6 +124,9 @@ namespace Avalonia.Controls
IconProperty.Changed.AddClassHandler((s, e) => s.PlatformImpl?.SetIcon(((WindowIcon)e.NewValue).PlatformImpl));
CanResizeProperty.Changed.AddClassHandler((w, e) => w.PlatformImpl?.CanResize((bool)e.NewValue));
+
+ WindowStateProperty.Changed.AddClassHandler(
+ (w, e) => { if (w.PlatformImpl != null) w.PlatformImpl.WindowState = (WindowState)e.NewValue; });
}
///
@@ -138,8 +147,11 @@ namespace Avalonia.Controls
impl.Closing = HandleClosing;
_maxPlatformClientSize = PlatformImpl?.MaxClientSize ?? default(Size);
Screens = new Screens(PlatformImpl?.Screen);
- }
+ if (PlatformImpl != null)
+ PlatformImpl.WindowStateChanged = s => WindowState = s;
+ }
+
///
event EventHandler INameScope.Registered
{
@@ -205,12 +217,8 @@ namespace Avalonia.Controls
///
public WindowState WindowState
{
- get { return PlatformImpl?.WindowState ?? WindowState.Normal; }
- set
- {
- if (PlatformImpl != null)
- PlatformImpl.WindowState = value;
- }
+ get { return GetValue(WindowStateProperty); }
+ set { SetValue(WindowStateProperty, value); }
}
///
diff --git a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs
index 9750b46aa2..ef16d06b60 100644
--- a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs
+++ b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs
@@ -42,6 +42,7 @@ namespace Avalonia.DesignerSupport.Remote
public Func Closing { get; set; }
public IPlatformHandle Handle { get; }
public WindowState WindowState { get; set; }
+ public Action WindowStateChanged { get; set; }
public Size MaxClientSize { get; } = new Size(4096, 4096);
public event Action LostFocus;
diff --git a/src/Avalonia.DesignerSupport/Remote/Stubs.cs b/src/Avalonia.DesignerSupport/Remote/Stubs.cs
index ee8569d748..e749d10468 100644
--- a/src/Avalonia.DesignerSupport/Remote/Stubs.cs
+++ b/src/Avalonia.DesignerSupport/Remote/Stubs.cs
@@ -32,6 +32,7 @@ namespace Avalonia.DesignerSupport.Remote
public Point Position { get; set; }
public Action PositionChanged { get; set; }
public WindowState WindowState { get; set; }
+ public Action WindowStateChanged { get; set; }
public IRenderer CreateRenderer(IRenderRoot root) => new ImmediateRenderer(root);
public void Dispose()
{
diff --git a/src/Avalonia.Layout/LayoutHelper.cs b/src/Avalonia.Layout/LayoutHelper.cs
index 8c0a6a579b..d77cc269f9 100644
--- a/src/Avalonia.Layout/LayoutHelper.cs
+++ b/src/Avalonia.Layout/LayoutHelper.cs
@@ -29,5 +29,34 @@ namespace Avalonia.Layout
height = Math.Max(height, control.MinHeight);
return new Size(width, height);
}
+
+ public static Size MeasureChild(ILayoutable control, Size availableSize, Thickness padding,
+ Thickness borderThickness)
+ {
+ return MeasureChild(control, availableSize, padding + borderThickness);
+ }
+
+ public static Size MeasureChild(ILayoutable control, Size availableSize, Thickness padding)
+ {
+ if (control != null)
+ {
+ control.Measure(availableSize.Deflate(padding));
+ return control.DesiredSize.Inflate(padding);
+ }
+
+ return new Size(padding.Left + padding.Right, padding.Bottom + padding.Top);
+ }
+
+ public static Size ArrangeChild(ILayoutable child, Size availableSize, Thickness padding, Thickness borderThickness)
+ {
+ return ArrangeChild(child, availableSize, padding + borderThickness);
+ }
+
+ public static Size ArrangeChild(ILayoutable child, Size availableSize, Thickness padding)
+ {
+ child?.Arrange(new Rect(availableSize).Deflate(padding));
+
+ return availableSize;
+ }
}
}
diff --git a/src/Avalonia.Themes.Default/ButtonSpinner.xaml b/src/Avalonia.Themes.Default/ButtonSpinner.xaml
index a08f5b5e9b..2558b7c2f8 100644
--- a/src/Avalonia.Themes.Default/ButtonSpinner.xaml
+++ b/src/Avalonia.Themes.Default/ButtonSpinner.xaml
@@ -46,12 +46,15 @@
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Margin="{TemplateBinding Padding}"
- HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
- VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
+ HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
+ VerticalAlignment="{TemplateBinding VerticalAlignment}">
+ Content="{TemplateBinding Content}"
+ HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
+ VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
+ Padding="{TemplateBinding Padding}"/>
@@ -68,8 +71,8 @@
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Margin="{TemplateBinding Padding}"
- HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
- VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
+ HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
+ VerticalAlignment="{TemplateBinding VerticalAlignment}">
@@ -77,7 +80,10 @@
+ Content="{TemplateBinding Content}"
+ HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
+ VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
+ Padding="{TemplateBinding Padding}"/>
diff --git a/src/Avalonia.Themes.Default/ContentControl.xaml b/src/Avalonia.Themes.Default/ContentControl.xaml
index 7584ae0dfe..d76eecee84 100644
--- a/src/Avalonia.Themes.Default/ContentControl.xaml
+++ b/src/Avalonia.Themes.Default/ContentControl.xaml
@@ -7,7 +7,9 @@
BorderThickness="{TemplateBinding BorderThickness}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
- Padding="{TemplateBinding Padding}"/>
+ Padding="{TemplateBinding Padding}"
+ VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
+ HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"/>
\ No newline at end of file
diff --git a/src/Avalonia.Themes.Default/Expander.xaml b/src/Avalonia.Themes.Default/Expander.xaml
index 5e05dcf608..0bea0c9763 100644
--- a/src/Avalonia.Themes.Default/Expander.xaml
+++ b/src/Avalonia.Themes.Default/Expander.xaml
@@ -18,8 +18,9 @@
IsVisible="{TemplateBinding IsExpanded}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
- HorizontalAlignment="Stretch"
- VerticalAlignment="Stretch" />
+ HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
+ VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
+ Padding="{TemplateBinding Padding}" />
@@ -36,8 +37,9 @@
IsVisible="{TemplateBinding IsExpanded}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
- HorizontalAlignment="Stretch"
- VerticalAlignment="Stretch" />
+ HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
+ VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
+ Padding="{TemplateBinding Padding}" />
@@ -54,8 +56,9 @@
IsVisible="{TemplateBinding IsExpanded}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
- HorizontalAlignment="Stretch"
- VerticalAlignment="Stretch" />
+ HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
+ VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
+ Padding="{TemplateBinding Padding}" />
@@ -72,8 +75,9 @@
IsVisible="{TemplateBinding IsExpanded}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
- HorizontalAlignment="Stretch"
- VerticalAlignment="Stretch" />
+ HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
+ VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
+ Padding="{TemplateBinding Padding}" />
@@ -94,7 +98,10 @@
Grid.Column="1"
Background="Transparent"
Content="{TemplateBinding Content}"
- VerticalAlignment="Center" />
+ VerticalAlignment="Center"
+ HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
+ VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
+ Padding="{TemplateBinding Padding}"/>
diff --git a/src/Avalonia.Themes.Default/ListBoxItem.xaml b/src/Avalonia.Themes.Default/ListBoxItem.xaml
index a0405f2875..fc2600c1a9 100644
--- a/src/Avalonia.Themes.Default/ListBoxItem.xaml
+++ b/src/Avalonia.Themes.Default/ListBoxItem.xaml
@@ -9,7 +9,9 @@
BorderThickness="{TemplateBinding BorderThickness}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
- Padding="{TemplateBinding Padding}"/>
+ Padding="{TemplateBinding Padding}"
+ VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
+ HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"/>
diff --git a/src/Avalonia.Themes.Default/RepeatButton.xaml b/src/Avalonia.Themes.Default/RepeatButton.xaml
index 872f390ac5..001c5c2f23 100644
--- a/src/Avalonia.Themes.Default/RepeatButton.xaml
+++ b/src/Avalonia.Themes.Default/RepeatButton.xaml
@@ -25,7 +25,7 @@
Padding="{TemplateBinding Padding}"
TextBlock.Foreground="{TemplateBinding Foreground}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
- VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" />
+ VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
diff --git a/src/Avalonia.Themes.Default/TabStripItem.xaml b/src/Avalonia.Themes.Default/TabStripItem.xaml
index 408cfaa3d7..8aa03d5bd2 100644
--- a/src/Avalonia.Themes.Default/TabStripItem.xaml
+++ b/src/Avalonia.Themes.Default/TabStripItem.xaml
@@ -11,6 +11,8 @@
BorderThickness="{TemplateBinding BorderThickness}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
+ HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
+ VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
Padding="{TemplateBinding Padding}"/>
diff --git a/src/Avalonia.Themes.Default/TreeViewItem.xaml b/src/Avalonia.Themes.Default/TreeViewItem.xaml
index 5fb1dfb73d..3a8fe344c5 100644
--- a/src/Avalonia.Themes.Default/TreeViewItem.xaml
+++ b/src/Avalonia.Themes.Default/TreeViewItem.xaml
@@ -13,6 +13,8 @@
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Content="{TemplateBinding Header}"
+ HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
+ VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
Padding="{TemplateBinding Padding}"
TemplatedControl.IsTemplateFocusTarget="True"
Grid.Column="1"/>
diff --git a/src/Avalonia.Themes.Default/Window.xaml b/src/Avalonia.Themes.Default/Window.xaml
index d19bf41c4d..f36e091e55 100644
--- a/src/Avalonia.Themes.Default/Window.xaml
+++ b/src/Avalonia.Themes.Default/Window.xaml
@@ -6,10 +6,12 @@
-
+ Content="{TemplateBinding Content}"
+ Margin="{TemplateBinding Padding}"
+ HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
+ VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
diff --git a/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs b/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs
index 0ebfea998a..94537d3475 100644
--- a/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs
+++ b/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs
@@ -241,7 +241,7 @@ namespace Avalonia.Gtk3
return true;
}
- void ConnectEvent(string name, Native.D.signal_onevent handler)
+ protected void ConnectEvent(string name, Native.D.signal_onevent handler)
=> Disposables.Add(Signal.Connect(GtkWidget, name, handler));
void Connect(string name, T handler) => Disposables.Add(Signal.Connect(GtkWidget, name, handler));
diff --git a/src/Gtk/Avalonia.Gtk3/WindowImpl.cs b/src/Gtk/Avalonia.Gtk3/WindowImpl.cs
index 2d309e19d4..bae34db6f3 100644
--- a/src/Gtk/Avalonia.Gtk3/WindowImpl.cs
+++ b/src/Gtk/Avalonia.Gtk3/WindowImpl.cs
@@ -1,18 +1,34 @@
using System;
-using System.Linq.Expressions;
using Avalonia.Controls;
using Avalonia.Gtk3.Interop;
using Avalonia.Platform;
-using System.Runtime.InteropServices;
namespace Avalonia.Gtk3
{
class WindowImpl : WindowBaseImpl, IWindowImpl
{
+ private WindowState _lastWindowState;
+
public WindowImpl() : base(Native.GtkWindowNew(GtkWindowType.TopLevel))
{
}
+ protected unsafe override bool OnStateChanged(IntPtr w, IntPtr pev, IntPtr userData)
+ {
+ var windowStateEvent = (GdkEventWindowState*)pev;
+ var newWindowState = windowStateEvent->new_window_state;
+ var windowState = newWindowState.HasFlag(GdkWindowState.Iconified) ? WindowState.Minimized
+ : (newWindowState.HasFlag(GdkWindowState.Maximized) ? WindowState.Maximized : WindowState.Normal);
+
+ if (windowState != _lastWindowState)
+ {
+ _lastWindowState = windowState;
+ WindowStateChanged?.Invoke(windowState);
+ }
+
+ return base.OnStateChanged(w, pev, userData);
+ }
+
public void SetTitle(string title)
{
using (var t = new Utf8Buffer(title))
@@ -43,7 +59,9 @@ namespace Avalonia.Gtk3
}
}
}
-
+
+ public Action WindowStateChanged { get; set; }
+
public IDisposable ShowDialog()
{
Native.GtkWindowSetModal(GtkWidget, true);
diff --git a/src/OSX/Avalonia.MonoMac/WindowImpl.cs b/src/OSX/Avalonia.MonoMac/WindowImpl.cs
index d01cbd6ae3..a2f8df6791 100644
--- a/src/OSX/Avalonia.MonoMac/WindowImpl.cs
+++ b/src/OSX/Avalonia.MonoMac/WindowImpl.cs
@@ -12,10 +12,24 @@ namespace Avalonia.MonoMac
public bool IsResizable = true;
public CGRect? UndecoratedLastUnmaximizedFrame;
+ private WindowState _lastWindowState;
+
public WindowImpl()
{
UpdateStyle();
Window.SetCanBecomeKeyAndMain();
+
+ Window.DidResize += delegate
+ {
+ var windowState = Window.IsMiniaturized ? WindowState.Minimized
+ : (IsZoomed ? WindowState.Maximized : WindowState.Normal);
+
+ if (windowState != _lastWindowState)
+ {
+ _lastWindowState = windowState;
+ WindowStateChanged?.Invoke(windowState);
+ }
+ };
}
public WindowState WindowState
@@ -49,6 +63,8 @@ namespace Avalonia.MonoMac
}
}
+ public Action WindowStateChanged { get; set; }
+
bool IsZoomed => IsDecorated ? Window.IsZoomed : UndecoratedIsMaximized;
public bool UndecoratedIsMaximized => Window.Frame == Window.Screen.VisibleFrame;
diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs
index be28b64c5a..7b9f8ee066 100644
--- a/src/Windows/Avalonia.Win32/WindowImpl.cs
+++ b/src/Windows/Avalonia.Win32/WindowImpl.cs
@@ -34,6 +34,7 @@ namespace Avalonia.Win32
private bool _resizable = true;
private double _scaling = 1;
private WindowState _showWindowState;
+ private WindowState _lastWindowState;
private FramebufferManager _framebuffer;
private OleDropTarget _dropTarget;
private Size _minSize;
@@ -77,6 +78,8 @@ namespace Avalonia.Win32
public Action PositionChanged { get; set; }
+ public Action WindowStateChanged { get; set; }
+
public Thickness BorderThickness
{
get
@@ -626,14 +629,25 @@ namespace Avalonia.Win32
return IntPtr.Zero;
case UnmanagedMethods.WindowsMessage.WM_SIZE:
+ var size = (UnmanagedMethods.SizeCommand)wParam;
+
if (Resized != null &&
- (wParam == (IntPtr)UnmanagedMethods.SizeCommand.Restored ||
- wParam == (IntPtr)UnmanagedMethods.SizeCommand.Maximized))
+ (size == UnmanagedMethods.SizeCommand.Restored ||
+ size == UnmanagedMethods.SizeCommand.Maximized))
{
var clientSize = new Size(ToInt32(lParam) & 0xffff, ToInt32(lParam) >> 16);
Resized(clientSize / Scaling);
}
+ var windowState = size == SizeCommand.Maximized ? WindowState.Maximized
+ : (size == SizeCommand.Minimized ? WindowState.Minimized : WindowState.Normal);
+
+ if (windowState != _lastWindowState)
+ {
+ _lastWindowState = windowState;
+ WindowStateChanged?.Invoke(windowState);
+ }
+
return IntPtr.Zero;
case UnmanagedMethods.WindowsMessage.WM_MOVE:
@@ -663,6 +677,7 @@ namespace Avalonia.Win32
(Screen as ScreenImpl)?.InvalidateScreensCache();
return IntPtr.Zero;
}
+
#if USE_MANAGED_DRAG
if (_managedDrag.PreprocessInputEvent(ref e))
diff --git a/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_Layout.cs b/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_Layout.cs
index 2c1074aa9a..98e57601a4 100644
--- a/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_Layout.cs
+++ b/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_Layout.cs
@@ -233,7 +233,7 @@ namespace Avalonia.Controls.UnitTests.Presenters
target.Arrange(new Rect(0, 0, 100, 100));
- Assert.Equal(new Rect(48, 48, 0, 0), content.Bounds);
+ Assert.Equal(new Rect(32, 32, 0, 0), content.Bounds);
}
}
}
\ No newline at end of file
diff --git a/tests/Avalonia.Markup.UnitTests/Data/BindingExpressionTests.cs b/tests/Avalonia.Markup.UnitTests/Data/BindingExpressionTests.cs
index f42e0daf2a..2e0f048e21 100644
--- a/tests/Avalonia.Markup.UnitTests/Data/BindingExpressionTests.cs
+++ b/tests/Avalonia.Markup.UnitTests/Data/BindingExpressionTests.cs
@@ -296,7 +296,7 @@ namespace Avalonia.Markup.UnitTests.Data
var data = new Class1 { DoubleValue = 5.6 };
var converter = new Mock();
var target = new BindingExpression(
- new ExpressionObserver(data, "DoubleValue"),
+ new ExpressionObserver(data, "DoubleValue"),
typeof(string),
converter.Object,
converterParameter: "foo");