Browse Source

Merge branch 'master' into wip-animations

Jumar Macato 7 years ago
parent
commit
586f345940
38 changed files with 396 additions and 309 deletions
  1. 1 1
      parameters.cake
  2. 3 2
      src/Avalonia.Base/AvaloniaObject.cs
  3. 0 2
      src/Avalonia.Controls/Avalonia.Controls.csproj
  4. 3 25
      src/Avalonia.Controls/Border.cs
  5. 3 14
      src/Avalonia.Controls/Decorator.cs
  6. 5 0
      src/Avalonia.Controls/Platform/IWindowImpl.cs
  7. 67 75
      src/Avalonia.Controls/Presenters/ContentPresenter.cs
  8. 117 137
      src/Avalonia.Controls/Utils/BorderRenderHelper.cs
  9. 17 9
      src/Avalonia.Controls/Window.cs
  10. 1 0
      src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs
  11. 1 0
      src/Avalonia.DesignerSupport/Remote/Stubs.cs
  12. 0 1
      src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.csproj
  13. 0 1
      src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.csproj
  14. 0 1
      src/Avalonia.HtmlRenderer/Avalonia.HtmlRenderer.csproj
  15. 29 0
      src/Avalonia.Layout/LayoutHelper.cs
  16. 12 6
      src/Avalonia.Themes.Default/ButtonSpinner.xaml
  17. 3 1
      src/Avalonia.Themes.Default/ContentControl.xaml
  18. 16 9
      src/Avalonia.Themes.Default/Expander.xaml
  19. 3 1
      src/Avalonia.Themes.Default/ListBoxItem.xaml
  20. 1 1
      src/Avalonia.Themes.Default/RepeatButton.xaml
  21. 2 0
      src/Avalonia.Themes.Default/TabStripItem.xaml
  22. 2 0
      src/Avalonia.Themes.Default/TreeViewItem.xaml
  23. 5 3
      src/Avalonia.Themes.Default/Window.xaml
  24. 1 1
      src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs
  25. 21 3
      src/Gtk/Avalonia.Gtk3/WindowImpl.cs
  26. 0 1
      src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
  27. 0 1
      src/Markup/Avalonia.Markup.Xaml/Properties/AssemblyInfo.cs
  28. 0 1
      src/Markup/Avalonia.Markup/Avalonia.Markup.csproj
  29. 0 1
      src/OSX/Avalonia.MonoMac/Avalonia.MonoMac.csproj
  30. 16 0
      src/OSX/Avalonia.MonoMac/WindowImpl.cs
  31. 0 1
      src/Skia/Avalonia.Skia/Avalonia.Skia.csproj
  32. 0 4
      src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj
  33. 0 1
      src/Windows/Avalonia.Direct2D1/Properties/AssemblyInfo.cs
  34. 17 2
      src/Windows/Avalonia.Win32/WindowImpl.cs
  35. 46 0
      tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Inheritance.cs
  36. 1 1
      tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_Layout.cs
  37. 2 2
      tests/Avalonia.DesignerSupport.Tests/DesignerSupportTests.cs
  38. 1 1
      tests/Avalonia.Markup.UnitTests/Data/BindingExpressionTests.cs

+ 1 - 1
parameters.cake

@@ -115,7 +115,7 @@ public class Parameters
 
         FileZipSuffix = Version + ".zip";
         ZipCoreArtifacts = ZipRoot.CombineWithFilePath("Avalonia-" + FileZipSuffix);
-        ZipSourceControlCatalogDesktopDirs = (DirectoryPath)context.Directory("./samples/ControlCatalog.Desktop/bin/" + DirSuffix);
+        ZipSourceControlCatalogDesktopDirs = (DirectoryPath)context.Directory("./samples/ControlCatalog.Desktop/bin/" + DirSuffix + "/net461");
         ZipTargetControlCatalogDesktopDirs = ZipRoot.CombineWithFilePath("ControlCatalog.Desktop-" + FileZipSuffix);
     }
 }

+ 3 - 2
src/Avalonia.Base/AvaloniaObject.cs

@@ -139,8 +139,9 @@ namespace Avalonia
                     {
                         _inheritanceParent.PropertyChanged -= ParentPropertyChanged;
                     }
-
-                    var inherited = (from property in AvaloniaPropertyRegistry.Instance.GetRegistered(this)
+                    var properties = AvaloniaPropertyRegistry.Instance.GetRegistered(this)
+                        .Concat(AvaloniaPropertyRegistry.Instance.GetRegisteredAttached(this.GetType()));
+                    var inherited = (from property in properties
                                      where property.Inherits
                                      select new
                                      {

+ 0 - 2
src/Avalonia.Controls/Avalonia.Controls.csproj

@@ -1,8 +1,6 @@
 <Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
     <TargetFramework>netstandard2.0</TargetFramework>
-    <LangVersion>latest</LangVersion>
-    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
   </PropertyGroup>
   <ItemGroup>
     <ProjectReference Include="..\Avalonia.Animation\Avalonia.Animation.csproj" />

+ 3 - 25
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
         /// <returns>The desired size of the control.</returns>
         protected override Size MeasureOverride(Size availableSize)
         {
-            return MeasureOverrideImpl(availableSize, Child, Padding, BorderThickness);
+            return LayoutHelper.MeasureChild(Child, availableSize, Padding, BorderThickness);
         }
 
         /// <summary>
@@ -109,32 +110,9 @@ namespace Avalonia.Controls
         /// <returns>The space taken.</returns>
         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);
         }
     }
 }

+ 3 - 14
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
         /// <inheritdoc/>
         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);
         }
 
         /// <inheritdoc/>
         protected override Size ArrangeOverride(Size finalSize)
         {
-            Child?.Arrange(new Rect(finalSize).Deflate(Padding));
-            return finalSize;
+            return LayoutHelper.ArrangeChild(Child, finalSize, Padding);
         }
 
         /// <summary>

+ 5 - 0
src/Avalonia.Controls/Platform/IWindowImpl.cs

@@ -16,6 +16,11 @@ namespace Avalonia.Platform
         /// </summary>
         WindowState WindowState { get; set; }
 
+        /// <summary>
+        /// Gets or sets a method called when the minimized/maximized state of the window changes.
+        /// </summary>
+        Action<WindowState> WindowStateChanged { get; set; }
+
         /// <summary>
         /// Sets the title of the window.
         /// </summary>

+ 67 - 75
src/Avalonia.Controls/Presenters/ContentPresenter.cs

@@ -35,6 +35,13 @@ namespace Avalonia.Controls.Presenters
         public static readonly StyledProperty<Thickness> BorderThicknessProperty =
             Border.BorderThicknessProperty.AddOwner<ContentPresenter>();
 
+        /// <summary>
+        /// Defines the <see cref="CornerRadius"/> property.
+        /// </summary>
+        public static readonly StyledProperty<CornerRadius> CornerRadiusProperty =
+            Border.CornerRadiusProperty.AddOwner<ContentPresenter>();
+
+
         /// <summary>
         /// Defines the <see cref="Child"/> property.
         /// </summary>
@@ -55,12 +62,6 @@ namespace Avalonia.Controls.Presenters
         public static readonly StyledProperty<IDataTemplate> ContentTemplateProperty =
             ContentControl.ContentTemplateProperty.AddOwner<ContentPresenter>();
 
-        /// <summary>
-        /// Defines the <see cref="CornerRadius"/> property.
-        /// </summary>
-        public static readonly StyledProperty<CornerRadius> CornerRadiusProperty =
-            Border.CornerRadiusProperty.AddOwner<ContentPresenter>();
-
         /// <summary>
         /// Defines the <see cref="HorizontalContentAlignment"/> property.
         /// </summary>
@@ -90,19 +91,12 @@ namespace Avalonia.Controls.Presenters
         static ContentPresenter()
         {
             AffectsRender(BackgroundProperty, BorderBrushProperty, BorderThicknessProperty, CornerRadiusProperty);
-            AffectsMeasure(BorderThicknessProperty);
+            AffectsMeasure(BorderThicknessProperty, PaddingProperty);
             ContentProperty.Changed.AddClassHandler<ContentPresenter>(x => x.ContentChanged);
             ContentTemplateProperty.Changed.AddClassHandler<ContentPresenter>(x => x.ContentChanged);
             TemplatedParentProperty.Changed.AddClassHandler<ContentPresenter>(x => x.TemplatedParentChanged);
         }
 
-        /// <summary>
-        /// Initializes a new instance of the <see cref="ContentPresenter"/> class.
-        /// </summary>
-        public ContentPresenter()
-        {
-        }
-
         /// <summary>
         /// Gets or sets a brush with which to paint the background.
         /// </summary>
@@ -130,6 +124,15 @@ namespace Avalonia.Controls.Presenters
             set { SetValue(BorderThicknessProperty, value); }
         }
 
+        /// <summary>
+        /// Gets or sets the radius of the border rounded corners.
+        /// </summary>
+        public CornerRadius CornerRadius
+        {
+            get { return GetValue(CornerRadiusProperty); }
+            set { SetValue(CornerRadiusProperty, value); }
+        }
+
         /// <summary>
         /// Gets the control displayed by the presenter.
         /// </summary>
@@ -159,16 +162,7 @@ namespace Avalonia.Controls.Presenters
         }
 
         /// <summary>
-        /// Gets or sets the radius of the border rounded corners.
-        /// </summary>
-        public CornerRadius CornerRadius
-        {
-            get { return GetValue(CornerRadiusProperty); }
-            set { SetValue(CornerRadiusProperty, value); }
-        }
-
-        /// <summary>
-        /// 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.
         /// </summary>
         public HorizontalAlignment HorizontalContentAlignment
         {
@@ -177,7 +171,7 @@ namespace Avalonia.Controls.Presenters
         }
 
         /// <summary>
-        /// 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.
         /// </summary>
         public VerticalAlignment VerticalContentAlignment
         {
@@ -186,7 +180,7 @@ namespace Avalonia.Controls.Presenters
         }
 
         /// <summary>
-        /// Gets or sets the padding to place around the <see cref="Child"/> control.
+        /// Gets or sets the space between the border and the <see cref="Child"/> control.
         /// </summary>
         public Thickness Padding
         {
@@ -195,7 +189,7 @@ namespace Avalonia.Controls.Presenters
         }
 
         /// <inheritdoc/>
-        public override sealed void ApplyTemplate()
+        public sealed override void ApplyTemplate()
         {
             if (!_createdChild && ((ILogical)this).IsAttachedToLogicalTree)
             {
@@ -328,96 +322,68 @@ namespace Avalonia.Controls.Presenters
         /// <inheritdoc/>
         protected override Size MeasureOverride(Size availableSize)
         {
-            return Border.MeasureOverrideImpl(availableSize, Child, Padding, BorderThickness);
+            return LayoutHelper.MeasureChild(Child, availableSize, Padding, BorderThickness);
         }
 
         /// <inheritdoc/>
         protected override Size ArrangeOverride(Size finalSize)
         {
-            finalSize = ArrangeOverrideImpl(finalSize, new Vector());
-
             _borderRenderer.Update(finalSize, BorderThickness, CornerRadius);
 
-            return finalSize;
-        }
-
-        /// <summary>
-        /// Called when the <see cref="Content"/> property changes.
-        /// </summary>
-        /// <param name="e">The event args.</param>
-        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;
         }
 
+        /// <summary>
+        /// Called when the <see cref="Content"/> property changes.
+        /// </summary>
+        /// <param name="e">The event args.</param>
+        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;

+ 117 - 137
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;
-        }
-
     }
 }

+ 17 - 9
src/Avalonia.Controls/Window.cs

@@ -67,13 +67,19 @@ namespace Avalonia.Controls
         /// </summary>
         public static readonly StyledProperty<bool> HasSystemDecorationsProperty =
             AvaloniaProperty.Register<Window, bool>(nameof(HasSystemDecorations), true);
-        
+
         /// <summary>
         /// Enables or disables the taskbar icon
         /// </summary>
         public static readonly StyledProperty<bool> ShowInTaskbarProperty =
             AvaloniaProperty.Register<Window, bool>(nameof(ShowInTaskbar), true);
-        
+
+        /// <summary>
+        /// Enables or disables the taskbar icon
+        /// </summary>
+        public static readonly StyledProperty<WindowState> WindowStateProperty =
+            AvaloniaProperty.Register<Window, WindowState>(nameof(WindowState));
+
         /// <summary>
         /// Defines the <see cref="Title"/> property.
         /// </summary>
@@ -118,6 +124,9 @@ namespace Avalonia.Controls
             IconProperty.Changed.AddClassHandler<Window>((s, e) => s.PlatformImpl?.SetIcon(((WindowIcon)e.NewValue).PlatformImpl));
 
             CanResizeProperty.Changed.AddClassHandler<Window>((w, e) => w.PlatformImpl?.CanResize((bool)e.NewValue));
+
+            WindowStateProperty.Changed.AddClassHandler<Window>(
+                (w, e) => { if (w.PlatformImpl != null) w.PlatformImpl.WindowState = (WindowState)e.NewValue; });
         }
 
         /// <summary>
@@ -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;
+        }
+        
         /// <inheritdoc/>
         event EventHandler<NameScopeEventArgs> INameScope.Registered
         {
@@ -205,12 +217,8 @@ namespace Avalonia.Controls
         /// </summary>
         public WindowState WindowState
         {
-            get { return PlatformImpl?.WindowState ?? WindowState.Normal; }
-            set
-            {
-                if (PlatformImpl != null)
-                    PlatformImpl.WindowState = value;
-            }
+            get { return GetValue(WindowStateProperty); }
+            set { SetValue(WindowStateProperty, value); }
         }
 
         /// <summary>

+ 1 - 0
src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs

@@ -42,6 +42,7 @@ namespace Avalonia.DesignerSupport.Remote
         public Func<bool> Closing { get; set; }
         public IPlatformHandle Handle { get; }
         public WindowState WindowState { get; set; }
+        public Action<WindowState> WindowStateChanged { get; set; }
         public Size MaxClientSize { get; } = new Size(4096, 4096);
         public event Action LostFocus;
 

+ 1 - 0
src/Avalonia.DesignerSupport/Remote/Stubs.cs

@@ -32,6 +32,7 @@ namespace Avalonia.DesignerSupport.Remote
         public Point Position { get; set; }
         public Action<Point> PositionChanged { get; set; }
         public WindowState WindowState { get; set; }
+        public Action<WindowState> WindowStateChanged { get; set; }
         public IRenderer CreateRenderer(IRenderRoot root) => new ImmediateRenderer(root);
         public void Dispose()
         {

+ 0 - 1
src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.csproj

@@ -1,7 +1,6 @@
 <Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
     <TargetFramework>netcoreapp2.0</TargetFramework>
-    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
     <DefineConstants>$(DefineConstants);DOTNETCORE</DefineConstants>
   </PropertyGroup>
   <ItemGroup>

+ 0 - 1
src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.csproj

@@ -1,7 +1,6 @@
 <Project Sdk="Microsoft.NET.Sdk">
     <PropertyGroup>
         <TargetFramework>net461</TargetFramework>
-        <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
         <DocumentationFile>bin\$(Configuration)\Avalonia.DotNetFrameworkRuntime.xml</DocumentationFile>
         <DefineConstants>$(DefineConstants);FULLDOTNET</DefineConstants>
         <TreatWarningsAsErrors>true</TreatWarningsAsErrors>

+ 0 - 1
src/Avalonia.HtmlRenderer/Avalonia.HtmlRenderer.csproj

@@ -3,7 +3,6 @@
     <TargetFramework>netstandard2.0</TargetFramework>
     <EnableDefaultCompileItems>False</EnableDefaultCompileItems>
     <EnableDefaultItems>False</EnableDefaultItems>
-    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
     <NoWarn>CS0436</NoWarn>
   </PropertyGroup>
   <ItemGroup>

+ 29 - 0
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;
+        }
     }
 }

+ 12 - 6
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}">
           <Grid ColumnDefinitions="*,Auto">
             <ContentPresenter Name="PART_ContentPresenter" Grid.Column="0"
                               ContentTemplate="{TemplateBinding ContentTemplate}"
-                              Content="{TemplateBinding Content}"/>
+                              Content="{TemplateBinding Content}"
+                              HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
+                              VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
+                              Padding="{TemplateBinding Padding}"/>
             <Grid Grid.Column="1" RowDefinitions="*,*" IsVisible="{TemplateBinding ShowButtonSpinner}">
               <RepeatButton Grid.Row="0" Name="PART_IncreaseButton"/>
               <RepeatButton Grid.Row="1" Name="PART_DecreaseButton"/>
@@ -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}">
           <Grid ColumnDefinitions="Auto,*">
             <Grid Grid.Column="0" RowDefinitions="*,*" IsVisible="{TemplateBinding ShowButtonSpinner}">
               <RepeatButton Grid.Row="0" Name="PART_IncreaseButton"/>
@@ -77,7 +80,10 @@
             </Grid>
             <ContentPresenter Name="PART_ContentPresenter" Grid.Column="1"
                               ContentTemplate="{TemplateBinding ContentTemplate}"
-                              Content="{TemplateBinding Content}"/>
+                              Content="{TemplateBinding Content}"
+                              HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
+                              VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
+                              Padding="{TemplateBinding Padding}"/>
           </Grid>
         </Border>
       </ControlTemplate>

+ 3 - 1
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}"/>
     </ControlTemplate>
   </Setter>
 </Style>

+ 16 - 9
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}" />
           </Grid>
         </Border>
       </ControlTemplate>
@@ -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}" />
           </Grid>
         </Border>
       </ControlTemplate>
@@ -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}" />
           </Grid>
         </Border>
       </ControlTemplate>
@@ -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}" />
           </Grid>
         </Border>
       </ControlTemplate>
@@ -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}"/>
           </Grid>
         </Border>
       </ControlTemplate>

+ 3 - 1
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}"/>
       </ControlTemplate>
     </Setter>
   </Style>

+ 1 - 1
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}"/>
             </ControlTemplate>
         </Setter>
     </Style>

+ 2 - 0
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}"/>
       </ControlTemplate>
     </Setter>

+ 2 - 0
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"/>

+ 5 - 3
src/Avalonia.Themes.Default/Window.xaml

@@ -6,10 +6,12 @@
     <ControlTemplate>
       <Border Background="{TemplateBinding Background}">
         <AdornerDecorator>
-          <ContentPresenter Name="PART_ContentPresenter" 
+          <ContentPresenter Name="PART_ContentPresenter"
                             ContentTemplate="{TemplateBinding ContentTemplate}"
-                            Content="{TemplateBinding Content}" 
-                            Margin="{TemplateBinding Padding}"/>
+                            Content="{TemplateBinding Content}"
+                            Margin="{TemplateBinding Padding}"
+                            HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
+                            VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>           
         </AdornerDecorator>
       </Border>
     </ControlTemplate>

+ 1 - 1
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<Native.D.signal_onevent>(GtkWidget, name, handler));
         void Connect<T>(string name, T handler) => Disposables.Add(Signal.Connect(GtkWidget, name, handler));
 

+ 21 - 3
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<WindowState> WindowStateChanged { get; set; }
+
         public IDisposable ShowDialog()
         {
             Native.GtkWindowSetModal(GtkWidget, true);

+ 0 - 1
src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj

@@ -3,7 +3,6 @@
     <TargetFramework>netstandard2.0</TargetFramework>
     <EnableDefaultCompileItems>False</EnableDefaultCompileItems>
     <EnableDefaultItems>false</EnableDefaultItems>
-    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
     <DebugSymbols>true</DebugSymbols>

+ 0 - 1
src/Markup/Avalonia.Markup.Xaml/Properties/AssemblyInfo.cs

@@ -5,7 +5,6 @@ using System.Reflection;
 using Avalonia.Metadata;
 using System.Runtime.CompilerServices;
 
-[assembly: AssemblyTitle("Avalonia.Markup.Xaml")]
 [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Markup.Xaml.Data")]
 [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Markup.Xaml.MarkupExtensions")]
 [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Markup.Xaml.Styling")]

+ 0 - 1
src/Markup/Avalonia.Markup/Avalonia.Markup.csproj

@@ -1,7 +1,6 @@
 <Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
     <TargetFramework>netstandard2.0</TargetFramework>
-    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
   </PropertyGroup>
   <ItemGroup>
     <ProjectReference Include="..\..\Avalonia.Base\Avalonia.Base.csproj" />

+ 0 - 1
src/OSX/Avalonia.MonoMac/Avalonia.MonoMac.csproj

@@ -2,7 +2,6 @@
   <PropertyGroup>
     <TargetFrameworks>netstandard2.0</TargetFrameworks>
     <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
-    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
   </PropertyGroup>
   <ItemGroup>
     <Compile Include="..\..\Shared\WindowResizeDragHelper.cs" Link="WindowResizeDragHelper.cs" />

+ 16 - 0
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<WindowState> WindowStateChanged { get; set; }
+
         bool IsZoomed => IsDecorated ? Window.IsZoomed : UndecoratedIsMaximized;
 
         public bool UndecoratedIsMaximized => Window.Frame == Window.Screen.VisibleFrame;

+ 0 - 1
src/Skia/Avalonia.Skia/Avalonia.Skia.csproj

@@ -1,7 +1,6 @@
 <Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
     <TargetFramework>netstandard2.0</TargetFramework>
-    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
     <RootNamespace>Avalonia.Skia</RootNamespace>
     <AssemblyName>Avalonia.Skia</AssemblyName>
     <IncludeLinuxSkia>true</IncludeLinuxSkia>

+ 0 - 4
src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj

@@ -1,12 +1,8 @@
 <Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
     <TargetFramework>netstandard2.0</TargetFramework>
-    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
   </PropertyGroup>
   <ItemGroup>
-    <Compile Include="..\..\Shared\SharedAssemblyInfo.cs">
-      <Link>Properties\SharedAssemblyInfo.cs</Link>
-    </Compile>
     <Compile Include="..\Avalonia.Win32\Interop\UnmanagedMethods.cs">
       <Link>UnmanagedMethods.cs</Link>
     </Compile>

+ 0 - 1
src/Windows/Avalonia.Direct2D1/Properties/AssemblyInfo.cs

@@ -5,7 +5,6 @@ using System.Reflection;
 using Avalonia.Platform;
 using Avalonia.Direct2D1;
 
-[assembly: AssemblyTitle("Avalonia.Direct2D1")]
 [assembly: ExportRenderingSubsystem(OperatingSystemType.WinNT, 1, "Direct2D1", typeof(Direct2D1Platform), nameof(Direct2D1Platform.Initialize),
     typeof(Direct2DChecker))]
 

+ 17 - 2
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<Point> PositionChanged { get; set; }
 
+        public Action<WindowState> 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))

+ 46 - 0
tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Inheritance.cs

@@ -38,6 +38,26 @@ namespace Avalonia.Base.UnitTests
             Assert.True(raised);
         }
 
+        [Fact]
+        public void Setting_InheritanceParent_Raises_PropertyChanged_For_Attached_Property_When_Value_Changed_In_Parent()
+        {
+            bool raised = false;
+
+            Class1 parent = new Class1();
+            parent.SetValue(AttachedOwner.AttachedProperty, "changed");
+
+            Class2 child = new Class2();
+            child.PropertyChanged += (s, e) =>
+                raised = s == child &&
+                         e.Property == AttachedOwner.AttachedProperty &&
+                         (string)e.OldValue == null &&
+                         (string)e.NewValue == "changed";
+
+            child.Parent = parent;
+
+            Assert.True(raised);
+        }
+
         [Fact]
         public void Setting_InheritanceParent_Doesnt_Raise_PropertyChanged_When_Local_Value_Set()
         {
@@ -75,6 +95,26 @@ namespace Avalonia.Base.UnitTests
             Assert.True(raised);
         }
 
+        [Fact]
+        public void Setting_Value_Of_Attached_Property_In_InheritanceParent_Raises_PropertyChanged()
+        {
+            bool raised = false;
+
+            Class1 parent = new Class1();
+
+            Class2 child = new Class2();
+            child.PropertyChanged += (s, e) =>
+                raised = s == child &&
+                         e.Property == AttachedOwner.AttachedProperty &&
+                         (string)e.OldValue == null &&
+                         (string)e.NewValue == "changed";
+            child.Parent = parent;
+
+            parent.SetValue(AttachedOwner.AttachedProperty, "changed");
+
+            Assert.True(raised);
+        }
+
         private class Class1 : AvaloniaObject
         {
             public static readonly StyledProperty<string> FooProperty =
@@ -97,5 +137,11 @@ namespace Avalonia.Base.UnitTests
                 set { InheritanceParent = value; }
             }
         }
+
+        private class AttachedOwner : AvaloniaObject
+        {
+            public static readonly AttachedProperty<string> AttachedProperty =
+                AvaloniaProperty.RegisterAttached<AttachedOwner, Class1, string>("Attached", inherits: true);
+        }
     }
 }

+ 1 - 1
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);
         }
     }
 }

+ 2 - 2
tests/Avalonia.DesignerSupport.Tests/DesignerSupportTests.cs

@@ -11,9 +11,9 @@ namespace Avalonia.DesignerSupport.Tests
 {
     public class DesignerSupportTests
     {
-        [Theory(Skip = "Skipping for now as failing on AppVeyor"),
+        [Theory,
          InlineData(@"Avalonia.DesignerSupport.TestApp.exe", @"..\..\tests\Avalonia.DesignerSupport.TestApp\MainWindow.xaml"),
-         InlineData(@"..\..\samples\ControlCatalog.Desktop\bin\$BUILD\ControlCatalog.dll", @"..\..\samples\ControlCatalog\MainWindow.xaml")]
+         InlineData(@"..\..\samples\ControlCatalog.Desktop\bin\$BUILD\net461\ControlCatalog.dll", @"..\..\samples\ControlCatalog\MainWindow.xaml")]
         public void DesignerApiShoudBeOperational(string outputDir, string xamlFile)
         {
             var xaml = File.ReadAllText(xamlFile);

+ 1 - 1
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<IValueConverter>();
             var target = new BindingExpression(
-                new ExpressionObserver(data, "DoubleValue"), 
+                new ExpressionObserver(data, "DoubleValue"),
                 typeof(string),
                 converter.Object,
                 converterParameter: "foo");