Browse Source

Merge branch 'master' into feature/layoutHelper

Steven Kirk 7 years ago
parent
commit
f60803275a
46 changed files with 222 additions and 86 deletions
  1. 1 1
      .travis.yml
  2. 1 0
      build/SharedVersion.props
  3. 1 1
      parameters.cake
  4. 8 2
      samples/ControlCatalog/Pages/TextBoxPage.xaml
  5. 3 2
      src/Avalonia.Base/AvaloniaObject.cs
  6. 0 2
      src/Avalonia.Controls/Avalonia.Controls.csproj
  7. 5 0
      src/Avalonia.Controls/Platform/IWindowImpl.cs
  8. 27 2
      src/Avalonia.Controls/Presenters/TextPresenter.cs
  9. 3 14
      src/Avalonia.Controls/Primitives/AccessText.cs
  10. 4 3
      src/Avalonia.Controls/TextBlock.cs
  11. 26 9
      src/Avalonia.Controls/TextBox.cs
  12. 17 9
      src/Avalonia.Controls/Window.cs
  13. 1 0
      src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs
  14. 1 0
      src/Avalonia.DesignerSupport/Remote/Stubs.cs
  15. 0 1
      src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.csproj
  16. 0 1
      src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.csproj
  17. 0 1
      src/Avalonia.HtmlRenderer/Avalonia.HtmlRenderer.csproj
  18. 4 3
      src/Avalonia.Themes.Default/TextBox.xaml
  19. 1 1
      src/Avalonia.Visuals/Matrix.cs
  20. 1 1
      src/Avalonia.Visuals/Media/Color.cs
  21. 2 2
      src/Avalonia.Visuals/Media/DrawingContext.cs
  22. 1 1
      src/Avalonia.Visuals/Media/Immutable/ImmutableSolidColorBrush.cs
  23. 1 1
      src/Avalonia.Visuals/Point.cs
  24. 1 1
      src/Avalonia.Visuals/Rect.cs
  25. 2 2
      src/Avalonia.Visuals/RelativePoint.cs
  26. 1 1
      src/Avalonia.Visuals/RelativeRect.cs
  27. 1 1
      src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs
  28. 1 1
      src/Avalonia.Visuals/Size.cs
  29. 1 1
      src/Avalonia.Visuals/Thickness.cs
  30. 1 1
      src/Avalonia.Visuals/Vector.cs
  31. 1 1
      src/Avalonia.Visuals/VisualTree/TransformedBounds.cs
  32. 1 1
      src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs
  33. 21 3
      src/Gtk/Avalonia.Gtk3/WindowImpl.cs
  34. 0 1
      src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
  35. 0 1
      src/Markup/Avalonia.Markup.Xaml/Properties/AssemblyInfo.cs
  36. 0 1
      src/Markup/Avalonia.Markup/Avalonia.Markup.csproj
  37. 0 1
      src/OSX/Avalonia.MonoMac/Avalonia.MonoMac.csproj
  38. 16 0
      src/OSX/Avalonia.MonoMac/WindowImpl.cs
  39. 1 1
      src/Shared/RenderHelpers/ArcToHelper.cs
  40. 0 1
      src/Skia/Avalonia.Skia/Avalonia.Skia.csproj
  41. 0 4
      src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj
  42. 1 1
      src/Windows/Avalonia.Direct2D1/OptionalDispose.cs
  43. 0 1
      src/Windows/Avalonia.Direct2D1/Properties/AssemblyInfo.cs
  44. 17 2
      src/Windows/Avalonia.Win32/WindowImpl.cs
  45. 46 0
      tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Inheritance.cs
  46. 2 2
      tests/Avalonia.DesignerSupport.Tests/DesignerSupportTests.cs

+ 1 - 1
.travis.yml

@@ -9,7 +9,7 @@ env:
     - DOTNET_CLI_TELEMETRY_OPTOUT=1
 mono:
   - 5.2.0
-dotnet: 2.0.0
+dotnet: 2.1.200
 script:
   - ./build.sh --target "Travis" --platform "NetCoreOnly" --configuration "Release"
 notifications:

+ 1 - 0
build/SharedVersion.props

@@ -9,5 +9,6 @@
     <RepositoryUrl>https://github.com/AvaloniaUI/Avalonia/</RepositoryUrl>
     <GenerateDocumentationFile>true</GenerateDocumentationFile>
     <NoWarn>CS1591</NoWarn>
+    <LangVersion>latest</LangVersion>
   </PropertyGroup>
 </Project>

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

+ 8 - 2
samples/ControlCatalog/Pages/TextBoxPage.xaml

@@ -10,10 +10,16 @@
       <StackPanel Orientation="Vertical" Gap="8">
         <TextBox Text="Lorem ipsum dolor sit amet, consectetur adipiscing elit." Width="200" />
         <TextBox Width="200" Watermark="Watermark" />
-        <TextBox Width="200" 
-                 Watermark="Floating Watermark" 
+        <TextBox Width="200"
+                 Watermark="Floating Watermark"
                  UseFloatingWatermark="True"
                  Text="Lorem ipsum dolor sit amet, consectetur adipiscing elit."/>
+
+        <TextBox Width="200"
+                 Watermark="Password Box"
+                 UseFloatingWatermark="True"
+                 PasswordChar="*"
+                 Text="Password" />
         <TextBox Width="200" Text="Left aligned text" TextAlignment="Left" />
         <TextBox Width="200" Text="Center aligned text" TextAlignment="Center" />
         <TextBox Width="200" Text="Right aligned text" TextAlignment="Right" />

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

+ 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>

+ 27 - 2
src/Avalonia.Controls/Presenters/TextPresenter.cs

@@ -17,6 +17,9 @@ namespace Avalonia.Controls.Presenters
                 o => o.CaretIndex,
                 (o, v) => o.CaretIndex = v);
 
+        public static readonly StyledProperty<char> PasswordCharProperty =
+            AvaloniaProperty.Register<TextPresenter, char>(nameof(PasswordChar));
+
         public static readonly DirectProperty<TextPresenter, int> SelectionStartProperty =
             TextBox.SelectionStartProperty.AddOwner<TextPresenter>(
                 o => o.SelectionStart,
@@ -63,6 +66,12 @@ namespace Avalonia.Controls.Presenters
             }
         }
 
+        public char PasswordChar
+        {
+            get => GetValue(PasswordCharProperty);
+            set => SetValue(PasswordCharProperty, value);
+        }
+
         public int SelectionStart
         {
             get
@@ -202,9 +211,25 @@ namespace Avalonia.Controls.Presenters
             }
         }
 
-        protected override FormattedText CreateFormattedText(Size constraint)
+        /// <summary>
+        /// Creates the <see cref="FormattedText"/> used to render the text.
+        /// </summary>
+        /// <param name="constraint">The constraint of the text.</param>
+        /// <param name="text">The text to generated the <see cref="FormattedText"/> for.</param>
+        /// <returns>A <see cref="FormattedText"/> object.</returns>
+        protected override FormattedText CreateFormattedText(Size constraint, string text)
         {
-            var result = base.CreateFormattedText(constraint);
+            FormattedText result = null;
+
+            if (PasswordChar != default(char))
+            {
+                result = base.CreateFormattedText(constraint, new string(PasswordChar, Text.Length));
+            }
+            else
+            {
+                result = base.CreateFormattedText(constraint, Text);
+            }
+
             var selectionStart = SelectionStart;
             var selectionEnd = SelectionEnd;
             var start = Math.Min(selectionStart, selectionEnd);

+ 3 - 14
src/Avalonia.Controls/Primitives/AccessText.cs

@@ -78,21 +78,10 @@ namespace Avalonia.Controls.Primitives
             }
         }
 
-        /// <summary>
-        /// Creates the <see cref="FormattedText"/> used to render the text.
-        /// </summary>
-        /// <param name="constraint">The constraint of the text.</param>
-        /// <returns>A <see cref="FormattedText"/> object.</returns>
-        protected override FormattedText CreateFormattedText(Size constraint)
+        /// <inheritdoc/>
+        protected override FormattedText CreateFormattedText(Size constraint, string text)
         {
-            return new FormattedText
-            {
-                Constraint = constraint,
-                Typeface = new Typeface(FontFamily, FontSize, FontStyle, FontWeight),
-                Text = StripAccessKey(Text),
-                TextAlignment = TextAlignment,
-                Wrapping = TextWrapping,
-            };
+            return base.CreateFormattedText(constraint, StripAccessKey(text));
         }
 
         /// <summary>

+ 4 - 3
src/Avalonia.Controls/TextBlock.cs

@@ -197,7 +197,7 @@ namespace Avalonia.Controls
             {
                 if (_formattedText == null)
                 {
-                    _formattedText = CreateFormattedText(_constraint);
+                    _formattedText = CreateFormattedText(_constraint, Text);
                 }
 
                 return _formattedText;
@@ -348,14 +348,15 @@ namespace Avalonia.Controls
         /// Creates the <see cref="FormattedText"/> used to render the text.
         /// </summary>
         /// <param name="constraint">The constraint of the text.</param>
+        /// <param name="text">The text to format.</param>
         /// <returns>A <see cref="FormattedText"/> object.</returns>
-        protected virtual FormattedText CreateFormattedText(Size constraint)
+        protected virtual FormattedText CreateFormattedText(Size constraint, string text)
         {
             return new FormattedText
             {
                 Constraint = constraint,
                 Typeface = new Typeface(FontFamily, FontSize, FontStyle, FontWeight),
-                Text = Text ?? string.Empty,
+                Text = text ?? string.Empty,
                 TextAlignment = TextAlignment,
                 Wrapping = TextWrapping,
             };

+ 26 - 9
src/Avalonia.Controls/TextBox.cs

@@ -30,10 +30,13 @@ namespace Avalonia.Controls
                 nameof(CaretIndex),
                 o => o.CaretIndex,
                 (o, v) => o.CaretIndex = v);
-        
+
         public static readonly StyledProperty<bool> IsReadOnlyProperty =
             AvaloniaProperty.Register<TextBox, bool>(nameof(IsReadOnly));
 
+        public static readonly StyledProperty<char> PasswordCharProperty =
+            AvaloniaProperty.Register<TextBox, char>(nameof(PasswordChar));
+
         public static readonly DirectProperty<TextBox, int> SelectionStartProperty =
             AvaloniaProperty.RegisterDirect<TextBox, int>(
                 nameof(SelectionStart),
@@ -87,7 +90,7 @@ namespace Avalonia.Controls
         private UndoRedoHelper<UndoRedoState> _undoRedoHelper;
         private bool _isUndoingRedoing;
         private bool _ignoreTextChanges;
-        private static readonly string[] invalidCharacters = new String[1]{"\u007f"};
+        private static readonly string[] invalidCharacters = new String[1] { "\u007f" };
 
         static TextBox()
         {
@@ -116,7 +119,7 @@ namespace Avalonia.Controls
                 ScrollViewer.HorizontalScrollBarVisibilityProperty,
                 horizontalScrollBarVisibility,
                 BindingPriority.Style);
-            _undoRedoHelper = new UndoRedoHelper<UndoRedoState>(this);
+            _undoRedoHelper = new UndoRedoHelper<UndoRedoState>(this);            
         }
 
         public bool AcceptsReturn
@@ -147,13 +150,19 @@ namespace Avalonia.Controls
                     _undoRedoHelper.UpdateLastState();
             }
         }
-        
+
         public bool IsReadOnly
         {
             get { return GetValue(IsReadOnlyProperty); }
             set { SetValue(IsReadOnlyProperty, value); }
         }
 
+        public char PasswordChar
+        {
+            get => GetValue(PasswordCharProperty);
+            set => SetValue(PasswordCharProperty, value);
+        }
+
         public int SelectionStart
         {
             get
@@ -237,7 +246,7 @@ namespace Avalonia.Controls
             _presenter = e.NameScope.Get<TextPresenter>("PART_TextPresenter");
             _presenter.Cursor = new Cursor(StandardCursorType.Ibeam);
 
-            if(IsFocused)
+            if (IsFocused)
             {
                 _presenter.ShowCaret();
             }
@@ -349,7 +358,10 @@ namespace Avalonia.Controls
                 case Key.C:
                     if (modifiers == InputModifiers.Control)
                     {
-                        Copy();
+                        if (!IsPasswordBox)
+                        {
+                            Copy();
+                        }
                         handled = true;
                     }
                     break;
@@ -357,8 +369,11 @@ namespace Avalonia.Controls
                 case Key.X:
                     if (modifiers == InputModifiers.Control)
                     {
-                        Copy();
-                        DeleteSelection();
+                        if (!IsPasswordBox)
+                        {
+                            Copy();
+                            DeleteSelection();
+                        }
                         handled = true;
                     }
                     break;
@@ -578,7 +593,7 @@ namespace Avalonia.Controls
                 DataValidationErrors.SetError(this, status.Error);
             }
         }
-        
+
         private int CoerceCaretIndex(int value) => CoerceCaretIndex(value, Text?.Length ?? 0);
 
         private int CoerceCaretIndex(int value, int length)
@@ -856,6 +871,8 @@ namespace Avalonia.Controls
             SelectionEnd = CaretIndex;
         }
 
+        private bool IsPasswordBox => PasswordChar != default(char);
+
         UndoRedoState UndoRedoHelper<UndoRedoState>.IUndoRedoHost.UndoRedoState
         {
             get { return new UndoRedoState(Text, CaretIndex); }

+ 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>

+ 4 - 3
src/Avalonia.Themes.Default/TextBox.xaml

@@ -11,7 +11,7 @@
                 BorderBrush="{TemplateBinding BorderBrush}"
                 BorderThickness="{TemplateBinding BorderThickness}">
           <DockPanel Margin="{TemplateBinding Padding}">
-            
+
             <TextBlock Name="floatingWatermark"
                        Foreground="{DynamicResource ThemeAccentBrush}"
                        FontSize="{DynamicResource FontSizeSmall}"
@@ -31,7 +31,7 @@
             <DataValidationErrors>
               <ScrollViewer HorizontalScrollBarVisibility="{TemplateBinding (ScrollViewer.HorizontalScrollBarVisibility)}"
                             VerticalScrollBarVisibility="{TemplateBinding (ScrollViewer.VerticalScrollBarVisibility)}">
-                
+
                 <Panel>
                   <TextBlock Name="watermark"
                              Opacity="0.5"
@@ -43,7 +43,8 @@
                                  SelectionStart="{TemplateBinding SelectionStart}"
                                  SelectionEnd="{TemplateBinding SelectionEnd}"
                                  TextAlignment="{TemplateBinding TextAlignment}"
-                                 TextWrapping="{TemplateBinding TextWrapping}"/>
+                                 TextWrapping="{TemplateBinding TextWrapping}"
+                                 PasswordChar="{TemplateBinding PasswordChar}"/>
                 </Panel>
               </ScrollViewer>
             </DataValidationErrors>

+ 1 - 1
src/Avalonia.Visuals/Matrix.cs

@@ -11,7 +11,7 @@ namespace Avalonia
     /// <summary>
     /// A 2x3 matrix.
     /// </summary>
-    public struct Matrix
+    public readonly struct Matrix
     {
         private readonly double _m11;
         private readonly double _m12;

+ 1 - 1
src/Avalonia.Visuals/Media/Color.cs

@@ -11,7 +11,7 @@ namespace Avalonia.Media
     /// <summary>
     /// An ARGB color.
     /// </summary>
-    public struct Color
+    public readonly struct Color
     {
         /// <summary>
         /// Gets or sets the Alpha component of the color.

+ 2 - 2
src/Avalonia.Visuals/Media/DrawingContext.cs

@@ -19,7 +19,7 @@ namespace Avalonia.Media
             ? new Stack<TransformContainer>()
             : TransformStackPool.Pop();
 
-        struct TransformContainer
+        readonly struct TransformContainer
         {
             public readonly Matrix LocalTransform;
             public readonly Matrix ContainerTransform;
@@ -147,7 +147,7 @@ namespace Avalonia.Media
             }
         }
 
-        public struct PushedState : IDisposable
+        public readonly struct PushedState : IDisposable
         {
             private readonly int _level;
             private readonly DrawingContext _context;

+ 1 - 1
src/Avalonia.Visuals/Media/Immutable/ImmutableSolidColorBrush.cs

@@ -6,7 +6,7 @@ namespace Avalonia.Media.Immutable
     /// <summary>
     /// Fills an area with a solid color.
     /// </summary>
-    public struct ImmutableSolidColorBrush : ISolidColorBrush
+    public readonly struct ImmutableSolidColorBrush : ISolidColorBrush
     {
         /// <summary>
         /// Initializes a new instance of the <see cref="ImmutableSolidColorBrush"/> class.

+ 1 - 1
src/Avalonia.Visuals/Point.cs

@@ -11,7 +11,7 @@ namespace Avalonia
     /// <summary>
     /// Defines a point.
     /// </summary>
-    public struct Point
+    public readonly struct Point
     {
         /// <summary>
         /// The X position.

+ 1 - 1
src/Avalonia.Visuals/Rect.cs

@@ -11,7 +11,7 @@ namespace Avalonia
     /// <summary>
     /// Defines a rectangle.
     /// </summary>
-    public struct Rect
+    public readonly struct Rect
     {
         /// <summary>
         /// An empty rectangle.

+ 2 - 2
src/Avalonia.Visuals/RelativePoint.cs

@@ -28,7 +28,7 @@ namespace Avalonia
     /// <summary>
     /// Defines a point that may be defined relative to a containing element.
     /// </summary>
-    public struct RelativePoint : IEquatable<RelativePoint>
+    public readonly struct RelativePoint : IEquatable<RelativePoint>
     {
         /// <summary>
         /// A point at the top left of the containing element.
@@ -45,7 +45,7 @@ namespace Avalonia
         /// </summary>
         public static readonly RelativePoint BottomRight = new RelativePoint(1, 1, RelativeUnit.Relative);
 
-        private Point _point;
+        private readonly Point _point;
 
         private readonly RelativeUnit _unit;
 

+ 1 - 1
src/Avalonia.Visuals/RelativeRect.cs

@@ -11,7 +11,7 @@ namespace Avalonia
     /// <summary>
     /// Defines a rectangle that may be defined relative to a containing element.
     /// </summary>
-    public struct RelativeRect : IEquatable<RelativeRect>
+    public readonly struct RelativeRect : IEquatable<RelativeRect>
     {
         private static readonly char[] PercentChar = { '%' };
 

+ 1 - 1
src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs

@@ -320,7 +320,7 @@ namespace Avalonia.Rendering.SceneGraph
             }
         }
 
-        public struct UpdateState : IDisposable
+        public readonly struct UpdateState : IDisposable
         {
             public UpdateState(
                 DeferredDrawingContextImpl owner,

+ 1 - 1
src/Avalonia.Visuals/Size.cs

@@ -11,7 +11,7 @@ namespace Avalonia
     /// <summary>
     /// Defines a size.
     /// </summary>
-    public struct Size
+    public readonly struct Size
     {
         /// <summary>
         /// A size representing infinity.

+ 1 - 1
src/Avalonia.Visuals/Thickness.cs

@@ -11,7 +11,7 @@ namespace Avalonia
     /// <summary>
     /// Describes the thickness of a frame around a rectangle.
     /// </summary>
-    public struct Thickness
+    public readonly struct Thickness
     {
         /// <summary>
         /// The thickness on the left.

+ 1 - 1
src/Avalonia.Visuals/Vector.cs

@@ -10,7 +10,7 @@ namespace Avalonia
     /// <summary>
     /// Defines a vector.
     /// </summary>
-    public struct Vector
+    public readonly struct Vector
     {
         /// <summary>
         /// The X vector.

+ 1 - 1
src/Avalonia.Visuals/VisualTree/TransformedBounds.cs

@@ -8,7 +8,7 @@ namespace Avalonia.VisualTree
     /// <summary>
     /// Holds information about the bounds of a control, together with a transform and a clip.
     /// </summary>
-    public struct TransformedBounds
+    public readonly struct TransformedBounds
     {
         /// <summary>
         /// Initializes a new instance of the <see cref="TransformedBounds"/> struct.

+ 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;

+ 1 - 1
src/Shared/RenderHelpers/ArcToHelper.cs

@@ -982,7 +982,7 @@ namespace Avalonia.RenderHelpers
             /// At some point I did not trust the WPF Matrix struct, and wrote my own simple one -_-
             /// This is supposed to be replaced with proper WPF Matrices everywhere
             /// </summary>
-            private struct SimpleMatrix
+            private readonly struct SimpleMatrix
             {
                 private readonly double _a, _b, _c, _d;
 

+ 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>

+ 1 - 1
src/Windows/Avalonia.Direct2D1/OptionalDispose.cs

@@ -2,7 +2,7 @@
 
 namespace Avalonia.Direct2D1
 {
-    public struct OptionalDispose<T> : IDisposable where T : IDisposable
+    public readonly struct OptionalDispose<T> : IDisposable where T : IDisposable
     {
         private readonly bool _dispose;
 

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

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