diff --git a/.travis.yml b/.travis.yml index fdffaba477..51b2aaf2bc 100644 --- a/.travis.yml +++ b/.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: diff --git a/build/SharedVersion.props b/build/SharedVersion.props index 8b7b02de5d..351583a106 100644 --- a/build/SharedVersion.props +++ b/build/SharedVersion.props @@ -9,5 +9,6 @@ https://github.com/AvaloniaUI/Avalonia/ true CS1591 + latest \ No newline at end of file diff --git a/parameters.cake b/parameters.cake index e224cce151..9e6eaa9d27 100644 --- a/parameters.cake +++ b/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); } } diff --git a/samples/ControlCatalog/Pages/TextBoxPage.xaml b/samples/ControlCatalog/Pages/TextBoxPage.xaml index 7bfcad6d51..db1c9cb69d 100644 --- a/samples/ControlCatalog/Pages/TextBoxPage.xaml +++ b/samples/ControlCatalog/Pages/TextBoxPage.xaml @@ -10,10 +10,16 @@ - + + diff --git a/src/Avalonia.Base/AvaloniaObject.cs b/src/Avalonia.Base/AvaloniaObject.cs index 68b9871fd1..1a2db9fc3d 100644 --- a/src/Avalonia.Base/AvaloniaObject.cs +++ b/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 { diff --git a/src/Avalonia.Controls/Avalonia.Controls.csproj b/src/Avalonia.Controls/Avalonia.Controls.csproj index ae777115f4..044ed47920 100644 --- a/src/Avalonia.Controls/Avalonia.Controls.csproj +++ b/src/Avalonia.Controls/Avalonia.Controls.csproj @@ -1,8 +1,6 @@  netstandard2.0 - latest - false diff --git a/src/Avalonia.Controls/Platform/IWindowImpl.cs b/src/Avalonia.Controls/Platform/IWindowImpl.cs index 3f2c977718..f1f3925133 100644 --- a/src/Avalonia.Controls/Platform/IWindowImpl.cs +++ b/src/Avalonia.Controls/Platform/IWindowImpl.cs @@ -16,6 +16,11 @@ namespace Avalonia.Platform /// WindowState WindowState { get; set; } + /// + /// Gets or sets a method called when the minimized/maximized state of the window changes. + /// + Action WindowStateChanged { get; set; } + /// /// Sets the title of the window. /// diff --git a/src/Avalonia.Controls/Presenters/TextPresenter.cs b/src/Avalonia.Controls/Presenters/TextPresenter.cs index d2d4151e3d..c241466aea 100644 --- a/src/Avalonia.Controls/Presenters/TextPresenter.cs +++ b/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 PasswordCharProperty = + AvaloniaProperty.Register(nameof(PasswordChar)); + public static readonly DirectProperty SelectionStartProperty = TextBox.SelectionStartProperty.AddOwner( 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) + /// + /// Creates the used to render the text. + /// + /// The constraint of the text. + /// The text to generated the for. + /// A object. + 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); diff --git a/src/Avalonia.Controls/Primitives/AccessText.cs b/src/Avalonia.Controls/Primitives/AccessText.cs index 4bb80e6d3f..32a0efc440 100644 --- a/src/Avalonia.Controls/Primitives/AccessText.cs +++ b/src/Avalonia.Controls/Primitives/AccessText.cs @@ -78,21 +78,10 @@ namespace Avalonia.Controls.Primitives } } - /// - /// Creates the used to render the text. - /// - /// The constraint of the text. - /// A object. - protected override FormattedText CreateFormattedText(Size constraint) + /// + 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)); } /// diff --git a/src/Avalonia.Controls/TextBlock.cs b/src/Avalonia.Controls/TextBlock.cs index 88a9fe077d..1fee309360 100644 --- a/src/Avalonia.Controls/TextBlock.cs +++ b/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 used to render the text. /// /// The constraint of the text. + /// The text to format. /// A object. - 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, }; diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index 890926db54..874d2a3229 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/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 IsReadOnlyProperty = AvaloniaProperty.Register(nameof(IsReadOnly)); + public static readonly StyledProperty PasswordCharProperty = + AvaloniaProperty.Register(nameof(PasswordChar)); + public static readonly DirectProperty SelectionStartProperty = AvaloniaProperty.RegisterDirect( nameof(SelectionStart), @@ -87,7 +90,7 @@ namespace Avalonia.Controls private UndoRedoHelper _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(this); + _undoRedoHelper = new UndoRedoHelper(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("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.IUndoRedoHost.UndoRedoState { get { return new UndoRedoState(Text, CaretIndex); } diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index 91d6c874d3..c4a09ac043 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -67,13 +67,19 @@ namespace Avalonia.Controls /// public static readonly StyledProperty HasSystemDecorationsProperty = AvaloniaProperty.Register(nameof(HasSystemDecorations), true); - + /// /// Enables or disables the taskbar icon /// public static readonly StyledProperty ShowInTaskbarProperty = AvaloniaProperty.Register(nameof(ShowInTaskbar), true); - + + /// + /// Enables or disables the taskbar icon + /// + public static readonly StyledProperty WindowStateProperty = + AvaloniaProperty.Register(nameof(WindowState)); + /// /// Defines the property. /// @@ -118,6 +124,9 @@ namespace Avalonia.Controls IconProperty.Changed.AddClassHandler((s, e) => s.PlatformImpl?.SetIcon(((WindowIcon)e.NewValue).PlatformImpl)); CanResizeProperty.Changed.AddClassHandler((w, e) => w.PlatformImpl?.CanResize((bool)e.NewValue)); + + WindowStateProperty.Changed.AddClassHandler( + (w, e) => { if (w.PlatformImpl != null) w.PlatformImpl.WindowState = (WindowState)e.NewValue; }); } /// @@ -138,8 +147,11 @@ namespace Avalonia.Controls impl.Closing = HandleClosing; _maxPlatformClientSize = PlatformImpl?.MaxClientSize ?? default(Size); Screens = new Screens(PlatformImpl?.Screen); - } + if (PlatformImpl != null) + PlatformImpl.WindowStateChanged = s => WindowState = s; + } + /// event EventHandler INameScope.Registered { @@ -205,12 +217,8 @@ namespace Avalonia.Controls /// public WindowState WindowState { - get { return PlatformImpl?.WindowState ?? WindowState.Normal; } - set - { - if (PlatformImpl != null) - PlatformImpl.WindowState = value; - } + get { return GetValue(WindowStateProperty); } + set { SetValue(WindowStateProperty, value); } } /// diff --git a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs index 9750b46aa2..ef16d06b60 100644 --- a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs +++ b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs @@ -42,6 +42,7 @@ namespace Avalonia.DesignerSupport.Remote public Func Closing { get; set; } public IPlatformHandle Handle { get; } public WindowState WindowState { get; set; } + public Action WindowStateChanged { get; set; } public Size MaxClientSize { get; } = new Size(4096, 4096); public event Action LostFocus; diff --git a/src/Avalonia.DesignerSupport/Remote/Stubs.cs b/src/Avalonia.DesignerSupport/Remote/Stubs.cs index ee8569d748..e749d10468 100644 --- a/src/Avalonia.DesignerSupport/Remote/Stubs.cs +++ b/src/Avalonia.DesignerSupport/Remote/Stubs.cs @@ -32,6 +32,7 @@ namespace Avalonia.DesignerSupport.Remote public Point Position { get; set; } public Action PositionChanged { get; set; } public WindowState WindowState { get; set; } + public Action WindowStateChanged { get; set; } public IRenderer CreateRenderer(IRenderRoot root) => new ImmediateRenderer(root); public void Dispose() { diff --git a/src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.csproj b/src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.csproj index 5f40d347b7..f80462e958 100644 --- a/src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.csproj +++ b/src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.csproj @@ -1,7 +1,6 @@  netcoreapp2.0 - false $(DefineConstants);DOTNETCORE diff --git a/src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.csproj b/src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.csproj index eca5b89419..34022a87f6 100644 --- a/src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.csproj +++ b/src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.csproj @@ -1,7 +1,6 @@  net461 - false bin\$(Configuration)\Avalonia.DotNetFrameworkRuntime.xml $(DefineConstants);FULLDOTNET true diff --git a/src/Avalonia.HtmlRenderer/Avalonia.HtmlRenderer.csproj b/src/Avalonia.HtmlRenderer/Avalonia.HtmlRenderer.csproj index 520687c3ef..6e65264db0 100644 --- a/src/Avalonia.HtmlRenderer/Avalonia.HtmlRenderer.csproj +++ b/src/Avalonia.HtmlRenderer/Avalonia.HtmlRenderer.csproj @@ -3,7 +3,6 @@ netstandard2.0 False False - false CS0436 diff --git a/src/Avalonia.Themes.Default/TextBox.xaml b/src/Avalonia.Themes.Default/TextBox.xaml index e228aebf58..c57e5b792d 100644 --- a/src/Avalonia.Themes.Default/TextBox.xaml +++ b/src/Avalonia.Themes.Default/TextBox.xaml @@ -11,7 +11,7 @@ BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"> - + - + + TextWrapping="{TemplateBinding TextWrapping}" + PasswordChar="{TemplateBinding PasswordChar}"/> diff --git a/src/Avalonia.Visuals/Matrix.cs b/src/Avalonia.Visuals/Matrix.cs index b09ea2b68c..9ed5923109 100644 --- a/src/Avalonia.Visuals/Matrix.cs +++ b/src/Avalonia.Visuals/Matrix.cs @@ -11,7 +11,7 @@ namespace Avalonia /// /// A 2x3 matrix. /// - public struct Matrix + public readonly struct Matrix { private readonly double _m11; private readonly double _m12; diff --git a/src/Avalonia.Visuals/Media/Color.cs b/src/Avalonia.Visuals/Media/Color.cs index 82cc19347a..aacce3fdce 100644 --- a/src/Avalonia.Visuals/Media/Color.cs +++ b/src/Avalonia.Visuals/Media/Color.cs @@ -11,7 +11,7 @@ namespace Avalonia.Media /// /// An ARGB color. /// - public struct Color + public readonly struct Color { /// /// Gets or sets the Alpha component of the color. diff --git a/src/Avalonia.Visuals/Media/DrawingContext.cs b/src/Avalonia.Visuals/Media/DrawingContext.cs index 1aa3fd21de..1d25224b8d 100644 --- a/src/Avalonia.Visuals/Media/DrawingContext.cs +++ b/src/Avalonia.Visuals/Media/DrawingContext.cs @@ -19,7 +19,7 @@ namespace Avalonia.Media ? new Stack() : 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; diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableSolidColorBrush.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableSolidColorBrush.cs index 015486c6a4..b55ca251a6 100644 --- a/src/Avalonia.Visuals/Media/Immutable/ImmutableSolidColorBrush.cs +++ b/src/Avalonia.Visuals/Media/Immutable/ImmutableSolidColorBrush.cs @@ -6,7 +6,7 @@ namespace Avalonia.Media.Immutable /// /// Fills an area with a solid color. /// - public struct ImmutableSolidColorBrush : ISolidColorBrush + public readonly struct ImmutableSolidColorBrush : ISolidColorBrush { /// /// Initializes a new instance of the class. diff --git a/src/Avalonia.Visuals/Point.cs b/src/Avalonia.Visuals/Point.cs index 62be3bf276..34070ac71f 100644 --- a/src/Avalonia.Visuals/Point.cs +++ b/src/Avalonia.Visuals/Point.cs @@ -11,7 +11,7 @@ namespace Avalonia /// /// Defines a point. /// - public struct Point + public readonly struct Point { /// /// The X position. diff --git a/src/Avalonia.Visuals/Rect.cs b/src/Avalonia.Visuals/Rect.cs index 73021ca29a..d28fff0216 100644 --- a/src/Avalonia.Visuals/Rect.cs +++ b/src/Avalonia.Visuals/Rect.cs @@ -11,7 +11,7 @@ namespace Avalonia /// /// Defines a rectangle. /// - public struct Rect + public readonly struct Rect { /// /// An empty rectangle. diff --git a/src/Avalonia.Visuals/RelativePoint.cs b/src/Avalonia.Visuals/RelativePoint.cs index e4d7ea05cb..5d3cb23a90 100644 --- a/src/Avalonia.Visuals/RelativePoint.cs +++ b/src/Avalonia.Visuals/RelativePoint.cs @@ -28,7 +28,7 @@ namespace Avalonia /// /// Defines a point that may be defined relative to a containing element. /// - public struct RelativePoint : IEquatable + public readonly struct RelativePoint : IEquatable { /// /// A point at the top left of the containing element. @@ -45,7 +45,7 @@ namespace Avalonia /// public static readonly RelativePoint BottomRight = new RelativePoint(1, 1, RelativeUnit.Relative); - private Point _point; + private readonly Point _point; private readonly RelativeUnit _unit; diff --git a/src/Avalonia.Visuals/RelativeRect.cs b/src/Avalonia.Visuals/RelativeRect.cs index ad42e30057..0afe74f0be 100644 --- a/src/Avalonia.Visuals/RelativeRect.cs +++ b/src/Avalonia.Visuals/RelativeRect.cs @@ -11,7 +11,7 @@ namespace Avalonia /// /// Defines a rectangle that may be defined relative to a containing element. /// - public struct RelativeRect : IEquatable + public readonly struct RelativeRect : IEquatable { private static readonly char[] PercentChar = { '%' }; diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs index dfd45fba9c..f3dbfbd8fb 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs +++ b/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, diff --git a/src/Avalonia.Visuals/Size.cs b/src/Avalonia.Visuals/Size.cs index b6889af6f0..50a3973a5c 100644 --- a/src/Avalonia.Visuals/Size.cs +++ b/src/Avalonia.Visuals/Size.cs @@ -11,7 +11,7 @@ namespace Avalonia /// /// Defines a size. /// - public struct Size + public readonly struct Size { /// /// A size representing infinity. diff --git a/src/Avalonia.Visuals/Thickness.cs b/src/Avalonia.Visuals/Thickness.cs index 43a5fed9e7..759abd5943 100644 --- a/src/Avalonia.Visuals/Thickness.cs +++ b/src/Avalonia.Visuals/Thickness.cs @@ -11,7 +11,7 @@ namespace Avalonia /// /// Describes the thickness of a frame around a rectangle. /// - public struct Thickness + public readonly struct Thickness { /// /// The thickness on the left. diff --git a/src/Avalonia.Visuals/Vector.cs b/src/Avalonia.Visuals/Vector.cs index c4545b8e5c..acde49a84a 100644 --- a/src/Avalonia.Visuals/Vector.cs +++ b/src/Avalonia.Visuals/Vector.cs @@ -10,7 +10,7 @@ namespace Avalonia /// /// Defines a vector. /// - public struct Vector + public readonly struct Vector { /// /// The X vector. diff --git a/src/Avalonia.Visuals/VisualTree/TransformedBounds.cs b/src/Avalonia.Visuals/VisualTree/TransformedBounds.cs index 435ca85a05..f8356bbcd6 100644 --- a/src/Avalonia.Visuals/VisualTree/TransformedBounds.cs +++ b/src/Avalonia.Visuals/VisualTree/TransformedBounds.cs @@ -8,7 +8,7 @@ namespace Avalonia.VisualTree /// /// Holds information about the bounds of a control, together with a transform and a clip. /// - public struct TransformedBounds + public readonly struct TransformedBounds { /// /// Initializes a new instance of the struct. diff --git a/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs b/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs index 0ebfea998a..94537d3475 100644 --- a/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs +++ b/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs @@ -241,7 +241,7 @@ namespace Avalonia.Gtk3 return true; } - void ConnectEvent(string name, Native.D.signal_onevent handler) + protected void ConnectEvent(string name, Native.D.signal_onevent handler) => Disposables.Add(Signal.Connect(GtkWidget, name, handler)); void Connect(string name, T handler) => Disposables.Add(Signal.Connect(GtkWidget, name, handler)); diff --git a/src/Gtk/Avalonia.Gtk3/WindowImpl.cs b/src/Gtk/Avalonia.Gtk3/WindowImpl.cs index 2d309e19d4..bae34db6f3 100644 --- a/src/Gtk/Avalonia.Gtk3/WindowImpl.cs +++ b/src/Gtk/Avalonia.Gtk3/WindowImpl.cs @@ -1,18 +1,34 @@ using System; -using System.Linq.Expressions; using Avalonia.Controls; using Avalonia.Gtk3.Interop; using Avalonia.Platform; -using System.Runtime.InteropServices; namespace Avalonia.Gtk3 { class WindowImpl : WindowBaseImpl, IWindowImpl { + private WindowState _lastWindowState; + public WindowImpl() : base(Native.GtkWindowNew(GtkWindowType.TopLevel)) { } + protected unsafe override bool OnStateChanged(IntPtr w, IntPtr pev, IntPtr userData) + { + var windowStateEvent = (GdkEventWindowState*)pev; + var newWindowState = windowStateEvent->new_window_state; + var windowState = newWindowState.HasFlag(GdkWindowState.Iconified) ? WindowState.Minimized + : (newWindowState.HasFlag(GdkWindowState.Maximized) ? WindowState.Maximized : WindowState.Normal); + + if (windowState != _lastWindowState) + { + _lastWindowState = windowState; + WindowStateChanged?.Invoke(windowState); + } + + return base.OnStateChanged(w, pev, userData); + } + public void SetTitle(string title) { using (var t = new Utf8Buffer(title)) @@ -43,7 +59,9 @@ namespace Avalonia.Gtk3 } } } - + + public Action WindowStateChanged { get; set; } + public IDisposable ShowDialog() { Native.GtkWindowSetModal(GtkWidget, true); diff --git a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj index 49f6ca9eeb..2d3a43a909 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj +++ b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj @@ -3,7 +3,6 @@ netstandard2.0 False false - false true diff --git a/src/Markup/Avalonia.Markup.Xaml/Properties/AssemblyInfo.cs b/src/Markup/Avalonia.Markup.Xaml/Properties/AssemblyInfo.cs index 0b42bedfa8..1b0e056baf 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Properties/AssemblyInfo.cs +++ b/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")] diff --git a/src/Markup/Avalonia.Markup/Avalonia.Markup.csproj b/src/Markup/Avalonia.Markup/Avalonia.Markup.csproj index 9707662701..a3b7d07784 100644 --- a/src/Markup/Avalonia.Markup/Avalonia.Markup.csproj +++ b/src/Markup/Avalonia.Markup/Avalonia.Markup.csproj @@ -1,7 +1,6 @@  netstandard2.0 - false diff --git a/src/OSX/Avalonia.MonoMac/Avalonia.MonoMac.csproj b/src/OSX/Avalonia.MonoMac/Avalonia.MonoMac.csproj index cbf91e818a..e675b43389 100644 --- a/src/OSX/Avalonia.MonoMac/Avalonia.MonoMac.csproj +++ b/src/OSX/Avalonia.MonoMac/Avalonia.MonoMac.csproj @@ -2,7 +2,6 @@ netstandard2.0 True - false diff --git a/src/OSX/Avalonia.MonoMac/WindowImpl.cs b/src/OSX/Avalonia.MonoMac/WindowImpl.cs index d01cbd6ae3..a2f8df6791 100644 --- a/src/OSX/Avalonia.MonoMac/WindowImpl.cs +++ b/src/OSX/Avalonia.MonoMac/WindowImpl.cs @@ -12,10 +12,24 @@ namespace Avalonia.MonoMac public bool IsResizable = true; public CGRect? UndecoratedLastUnmaximizedFrame; + private WindowState _lastWindowState; + public WindowImpl() { UpdateStyle(); Window.SetCanBecomeKeyAndMain(); + + Window.DidResize += delegate + { + var windowState = Window.IsMiniaturized ? WindowState.Minimized + : (IsZoomed ? WindowState.Maximized : WindowState.Normal); + + if (windowState != _lastWindowState) + { + _lastWindowState = windowState; + WindowStateChanged?.Invoke(windowState); + } + }; } public WindowState WindowState @@ -49,6 +63,8 @@ namespace Avalonia.MonoMac } } + public Action WindowStateChanged { get; set; } + bool IsZoomed => IsDecorated ? Window.IsZoomed : UndecoratedIsMaximized; public bool UndecoratedIsMaximized => Window.Frame == Window.Screen.VisibleFrame; diff --git a/src/Shared/RenderHelpers/ArcToHelper.cs b/src/Shared/RenderHelpers/ArcToHelper.cs index 9da47909cb..2457606f9d 100644 --- a/src/Shared/RenderHelpers/ArcToHelper.cs +++ b/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 /// - private struct SimpleMatrix + private readonly struct SimpleMatrix { private readonly double _a, _b, _c, _d; diff --git a/src/Skia/Avalonia.Skia/Avalonia.Skia.csproj b/src/Skia/Avalonia.Skia/Avalonia.Skia.csproj index ade7f8778a..03618e00f5 100644 --- a/src/Skia/Avalonia.Skia/Avalonia.Skia.csproj +++ b/src/Skia/Avalonia.Skia/Avalonia.Skia.csproj @@ -1,7 +1,6 @@  netstandard2.0 - false Avalonia.Skia Avalonia.Skia true diff --git a/src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj b/src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj index a84c373886..426a9a85a3 100644 --- a/src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj +++ b/src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj @@ -1,12 +1,8 @@  netstandard2.0 - false - - Properties\SharedAssemblyInfo.cs - UnmanagedMethods.cs diff --git a/src/Windows/Avalonia.Direct2D1/OptionalDispose.cs b/src/Windows/Avalonia.Direct2D1/OptionalDispose.cs index cd3eee8d25..e302e71102 100644 --- a/src/Windows/Avalonia.Direct2D1/OptionalDispose.cs +++ b/src/Windows/Avalonia.Direct2D1/OptionalDispose.cs @@ -2,7 +2,7 @@ namespace Avalonia.Direct2D1 { - public struct OptionalDispose : IDisposable where T : IDisposable + public readonly struct OptionalDispose : IDisposable where T : IDisposable { private readonly bool _dispose; diff --git a/src/Windows/Avalonia.Direct2D1/Properties/AssemblyInfo.cs b/src/Windows/Avalonia.Direct2D1/Properties/AssemblyInfo.cs index c1c5b24048..a09d5c2d1c 100644 --- a/src/Windows/Avalonia.Direct2D1/Properties/AssemblyInfo.cs +++ b/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))] diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index be28b64c5a..7b9f8ee066 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -34,6 +34,7 @@ namespace Avalonia.Win32 private bool _resizable = true; private double _scaling = 1; private WindowState _showWindowState; + private WindowState _lastWindowState; private FramebufferManager _framebuffer; private OleDropTarget _dropTarget; private Size _minSize; @@ -77,6 +78,8 @@ namespace Avalonia.Win32 public Action PositionChanged { get; set; } + public Action WindowStateChanged { get; set; } + public Thickness BorderThickness { get @@ -626,14 +629,25 @@ namespace Avalonia.Win32 return IntPtr.Zero; case UnmanagedMethods.WindowsMessage.WM_SIZE: + var size = (UnmanagedMethods.SizeCommand)wParam; + if (Resized != null && - (wParam == (IntPtr)UnmanagedMethods.SizeCommand.Restored || - wParam == (IntPtr)UnmanagedMethods.SizeCommand.Maximized)) + (size == UnmanagedMethods.SizeCommand.Restored || + size == UnmanagedMethods.SizeCommand.Maximized)) { var clientSize = new Size(ToInt32(lParam) & 0xffff, ToInt32(lParam) >> 16); Resized(clientSize / Scaling); } + var windowState = size == SizeCommand.Maximized ? WindowState.Maximized + : (size == SizeCommand.Minimized ? WindowState.Minimized : WindowState.Normal); + + if (windowState != _lastWindowState) + { + _lastWindowState = windowState; + WindowStateChanged?.Invoke(windowState); + } + return IntPtr.Zero; case UnmanagedMethods.WindowsMessage.WM_MOVE: @@ -663,6 +677,7 @@ namespace Avalonia.Win32 (Screen as ScreenImpl)?.InvalidateScreensCache(); return IntPtr.Zero; } + #if USE_MANAGED_DRAG if (_managedDrag.PreprocessInputEvent(ref e)) diff --git a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Inheritance.cs b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Inheritance.cs index 5bd888eeb4..ef6e03a60b 100644 --- a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Inheritance.cs +++ b/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 FooProperty = @@ -97,5 +137,11 @@ namespace Avalonia.Base.UnitTests set { InheritanceParent = value; } } } + + private class AttachedOwner : AvaloniaObject + { + public static readonly AttachedProperty AttachedProperty = + AvaloniaProperty.RegisterAttached("Attached", inherits: true); + } } } diff --git a/tests/Avalonia.DesignerSupport.Tests/DesignerSupportTests.cs b/tests/Avalonia.DesignerSupport.Tests/DesignerSupportTests.cs index 32da700acc..f320fa6fe8 100644 --- a/tests/Avalonia.DesignerSupport.Tests/DesignerSupportTests.cs +++ b/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);