From 49aeb7cec2de6145d4c0f8c842ac7211c454d444 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Fri, 19 May 2017 13:49:11 +0300 Subject: [PATCH 01/23] Fixed binding to Task --- src/Markup/Avalonia.Markup/Data/Plugins/TaskStreamPlugin.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Markup/Avalonia.Markup/Data/Plugins/TaskStreamPlugin.cs b/src/Markup/Avalonia.Markup/Data/Plugins/TaskStreamPlugin.cs index d2c8c1b064..02fe8104b8 100644 --- a/src/Markup/Avalonia.Markup/Data/Plugins/TaskStreamPlugin.cs +++ b/src/Markup/Avalonia.Markup/Data/Plugins/TaskStreamPlugin.cs @@ -36,7 +36,7 @@ namespace Avalonia.Markup.Data.Plugins if (task != null) { - var resultProperty = task.GetType().GetTypeInfo().GetDeclaredProperty("Result"); + var resultProperty = task.GetType().GetRuntimeProperty("Result"); if (resultProperty != null) { @@ -61,7 +61,7 @@ namespace Avalonia.Markup.Data.Plugins protected IObservable HandleCompleted(Task task) { - var resultProperty = task.GetType().GetTypeInfo().GetDeclaredProperty("Result"); + var resultProperty = task.GetType().GetRuntimeProperty("Result"); if (resultProperty != null) { From 760caf86ce9145772e60dfe94eea02e270215664 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Fri, 19 May 2017 14:01:34 +0300 Subject: [PATCH 02/23] Bump version --- src/Shared/SharedAssemblyInfo.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Shared/SharedAssemblyInfo.cs b/src/Shared/SharedAssemblyInfo.cs index 2ae067092c..81c31e2687 100644 --- a/src/Shared/SharedAssemblyInfo.cs +++ b/src/Shared/SharedAssemblyInfo.cs @@ -13,6 +13,6 @@ using System.Resources; [assembly: AssemblyTrademark("")] [assembly: NeutralResourcesLanguage("en")] -[assembly: AssemblyVersion("0.5.0")] -[assembly: AssemblyFileVersion("0.5.0")] -[assembly: AssemblyInformationalVersion("0.5.0")] +[assembly: AssemblyVersion("0.5.1")] +[assembly: AssemblyFileVersion("0.5.1")] +[assembly: AssemblyInformationalVersion("0.5.1")] From 4ecca2bb53fa4107ae1611d1a874eee14dc20145 Mon Sep 17 00:00:00 2001 From: Connor Laderer Date: Wed, 24 May 2017 22:08:33 -0400 Subject: [PATCH 03/23] Added overload of Start for AppBuilderBase This will allow for easy use of Dependency Injection with Microsoft.Extensions.DependencyInjection the mainWindow can resolve any constructor objects it may have. --- src/Avalonia.Controls/AppBuilderBase.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/Avalonia.Controls/AppBuilderBase.cs b/src/Avalonia.Controls/AppBuilderBase.cs index 97de093a59..13e9c108e1 100644 --- a/src/Avalonia.Controls/AppBuilderBase.cs +++ b/src/Avalonia.Controls/AppBuilderBase.cs @@ -129,6 +129,24 @@ namespace Avalonia.Controls Instance.Run(window); } + /// + /// Starts the application with the provided instance of . + /// + /// The window type. + /// Instance of type TMainWindow to use when starting the app + /// A delegate that will be called to create a data context for the window (optional). + public void Start(TMainWindow mainWindow, Func dataContextProvider = null) + where TMainWindow : Window, new() + { + Setup(); + BeforeStartCallback(Self); + + if (dataContextProvider != null) + mainWindow.DataContext = dataContextProvider(); + mainWindow.Show(); + Instance.Run(mainWindow); + } + /// /// Sets up the platform-specific services for the application, but does not run it. /// From 0a65816ae1fe37dcbe585469235f98449b1f2d25 Mon Sep 17 00:00:00 2001 From: Connor Laderer Date: Wed, 24 May 2017 22:19:14 -0400 Subject: [PATCH 04/23] Corrected where statement because if its provided, it doesn't need a parameterless constructor --- src/Avalonia.Controls/AppBuilderBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/AppBuilderBase.cs b/src/Avalonia.Controls/AppBuilderBase.cs index 13e9c108e1..30ef7dc427 100644 --- a/src/Avalonia.Controls/AppBuilderBase.cs +++ b/src/Avalonia.Controls/AppBuilderBase.cs @@ -136,7 +136,7 @@ namespace Avalonia.Controls /// Instance of type TMainWindow to use when starting the app /// A delegate that will be called to create a data context for the window (optional). public void Start(TMainWindow mainWindow, Func dataContextProvider = null) - where TMainWindow : Window, new() + where TMainWindow : Window { Setup(); BeforeStartCallback(Self); From 15c3ef499bca1c57b09a7b6b291382cf5633e38d Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 26 May 2017 00:47:34 +0200 Subject: [PATCH 05/23] Added failing test for #993. --- .../Avalonia.Layout.UnitTests/MeasureTests.cs | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/tests/Avalonia.Layout.UnitTests/MeasureTests.cs b/tests/Avalonia.Layout.UnitTests/MeasureTests.cs index b5a3539da9..570628b5b7 100644 --- a/tests/Avalonia.Layout.UnitTests/MeasureTests.cs +++ b/tests/Avalonia.Layout.UnitTests/MeasureTests.cs @@ -100,5 +100,58 @@ namespace Avalonia.Layout.UnitTests Assert.Equal(0, target.DesiredSize.Height); } + + [Fact] + public void Margin_Should_Affect_AvailableSize() + { + MeasureTest target; + + var outer = new Decorator + { + Width = 100, + Height = 100, + Child = target = new MeasureTest + { + Margin = new Thickness(10), + } + }; + + outer.Measure(Size.Infinity); + + Assert.Equal(new Size(80, 80), target.AvailableSize); + } + + [Fact] + public void Margin_Should_Be_Applied_Before_Width_Height() + { + MeasureTest target; + + var outer = new Decorator + { + Width = 100, + Height = 100, + Child = target = new MeasureTest + { + Width = 80, + Height = 80, + Margin = new Thickness(10), + } + }; + + outer.Measure(Size.Infinity); + + Assert.Equal(new Size(80, 80), target.AvailableSize); + } + + class MeasureTest : Control + { + public Size? AvailableSize { get; private set; } + + protected override Size MeasureOverride(Size availableSize) + { + AvailableSize = availableSize; + return availableSize; + } + } } } From 16a47dac6150c4a78045c46f562cb93dcc2edc9f Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 26 May 2017 00:49:28 +0200 Subject: [PATCH 06/23] Apply margin before width/height. Fixes #993. --- src/Avalonia.Layout/Layoutable.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Avalonia.Layout/Layoutable.cs b/src/Avalonia.Layout/Layoutable.cs index 5abd6c52f7..95a0dd625c 100644 --- a/src/Avalonia.Layout/Layoutable.cs +++ b/src/Avalonia.Layout/Layoutable.cs @@ -456,10 +456,9 @@ namespace Avalonia.Layout ApplyTemplate(); - var constrained = LayoutHelper - .ApplyLayoutConstraints(this, availableSize) - .Deflate(margin); - + var constrained = LayoutHelper.ApplyLayoutConstraints( + this, + availableSize.Deflate(margin)); var measured = MeasureOverride(constrained); var width = measured.Width; From 4fa6c1e7f4f89a6f975427ef0ebcb15da35b5789 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 26 May 2017 00:53:37 +0200 Subject: [PATCH 07/23] Fixed invalid doc references. --- src/Avalonia.Controls/AppBuilderBase.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Avalonia.Controls/AppBuilderBase.cs b/src/Avalonia.Controls/AppBuilderBase.cs index 30ef7dc427..1610d33f9b 100644 --- a/src/Avalonia.Controls/AppBuilderBase.cs +++ b/src/Avalonia.Controls/AppBuilderBase.cs @@ -55,8 +55,7 @@ namespace Avalonia.Controls public Action AfterSetupCallback { get; private set; } = builder => { }; /// - /// Gets or sets a method to call before is called on the - /// . + /// Gets or sets a method to call before Startis called on the . /// public Action BeforeStartCallback { get; private set; } = builder => { }; @@ -94,8 +93,7 @@ namespace Avalonia.Controls protected TAppBuilder Self => (TAppBuilder) this; /// - /// Registers a callback to call before is called on the - /// . + /// Registers a callback to call before Start is called on the . /// /// The callback. /// An instance. From e883107ca35a1965572acbb933977be307fffce7 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Fri, 26 May 2017 15:03:09 +0300 Subject: [PATCH 08/23] Make PlatformImpl nullable and always check for null value --- .../Direct3DInteropSample/MainWindow.cs | 2 +- .../Embedding/EmbeddableControlRoot.cs | 12 +++---- src/Avalonia.Controls/Primitives/PopupRoot.cs | 7 ++-- src/Avalonia.Controls/TopLevel.cs | 33 ++++++++++-------- src/Avalonia.Controls/Window.cs | 28 +++++++++------ src/Avalonia.Controls/WindowBase.cs | 34 +++++++++++-------- .../DesignerAssist.cs | 4 ++- .../Embedding/WinFormsAvaloniaControlHost.cs | 4 ++- 8 files changed, 71 insertions(+), 53 deletions(-) diff --git a/samples/interop/Direct3DInteropSample/MainWindow.cs b/samples/interop/Direct3DInteropSample/MainWindow.cs index 1ff1e1938b..ad40e81895 100644 --- a/samples/interop/Direct3DInteropSample/MainWindow.cs +++ b/samples/interop/Direct3DInteropSample/MainWindow.cs @@ -58,7 +58,7 @@ namespace Direct3DInteropSample new ModeDescription((int)ClientSize.Width, (int)ClientSize.Height, new Rational(60, 1), Format.R8G8B8A8_UNorm), IsWindowed = true, - OutputHandle = PlatformImpl.Handle.Handle, + OutputHandle = PlatformImpl?.Handle.Handle ?? IntPtr.Zero, SampleDescription = new SampleDescription(1, 0), SwapEffect = SwapEffect.Discard, Usage = Usage.RenderTargetOutput diff --git a/src/Avalonia.Controls/Embedding/EmbeddableControlRoot.cs b/src/Avalonia.Controls/Embedding/EmbeddableControlRoot.cs index 4688017187..b8d54fa67b 100644 --- a/src/Avalonia.Controls/Embedding/EmbeddableControlRoot.cs +++ b/src/Avalonia.Controls/Embedding/EmbeddableControlRoot.cs @@ -4,6 +4,7 @@ using Avalonia.Input; using Avalonia.Layout; using Avalonia.Platform; using Avalonia.Styling; +using JetBrains.Annotations; namespace Avalonia.Controls.Embedding { @@ -18,6 +19,7 @@ namespace Avalonia.Controls.Embedding { } + [CanBeNull] public new IEmbeddableWindowImpl PlatformImpl => (IEmbeddableWindowImpl) base.PlatformImpl; public void Prepare() @@ -39,8 +41,9 @@ namespace Avalonia.Controls.Embedding protected override Size MeasureOverride(Size availableSize) { - base.MeasureOverride(PlatformImpl.ClientSize); - return PlatformImpl.ClientSize; + var cs = PlatformImpl?.ClientSize ?? default(Size); + base.MeasureOverride(cs); + return cs; } private readonly NameScope _nameScope = new NameScope(); @@ -63,9 +66,6 @@ namespace Avalonia.Controls.Embedding public void Unregister(string name) => _nameScope.Unregister(name); Type IStyleable.StyleKey => typeof(EmbeddableControlRoot); - public void Dispose() - { - PlatformImpl.Dispose(); - } + public void Dispose() => PlatformImpl?.Dispose(); } } diff --git a/src/Avalonia.Controls/Primitives/PopupRoot.cs b/src/Avalonia.Controls/Primitives/PopupRoot.cs index 86c1b47521..a999e4ae37 100644 --- a/src/Avalonia.Controls/Primitives/PopupRoot.cs +++ b/src/Avalonia.Controls/Primitives/PopupRoot.cs @@ -9,6 +9,7 @@ using Avalonia.Layout; using Avalonia.Media; using Avalonia.Platform; using Avalonia.VisualTree; +using JetBrains.Annotations; namespace Avalonia.Controls.Primitives { @@ -49,6 +50,7 @@ namespace Avalonia.Controls.Primitives /// /// Gets the platform-specific window implementation. /// + [CanBeNull] public new IPopupImpl PlatformImpl => (IPopupImpl)base.PlatformImpl; /// @@ -65,10 +67,7 @@ namespace Avalonia.Controls.Primitives IVisual IHostedVisualTreeRoot.Host => Parent; /// - public void Dispose() - { - this.PlatformImpl.Dispose(); - } + public void Dispose() => PlatformImpl?.Dispose(); /// protected override void OnTemplateApplied(TemplateAppliedEventArgs e) diff --git a/src/Avalonia.Controls/TopLevel.cs b/src/Avalonia.Controls/TopLevel.cs index f3a6ab92d0..53dd905eca 100644 --- a/src/Avalonia.Controls/TopLevel.cs +++ b/src/Avalonia.Controls/TopLevel.cs @@ -14,6 +14,7 @@ using Avalonia.Platform; using Avalonia.Rendering; using Avalonia.Styling; using Avalonia.VisualTree; +using JetBrains.Annotations; namespace Avalonia.Controls { @@ -92,13 +93,13 @@ namespace Avalonia.Controls var rendererFactory = TryGetService(dependencyResolver); Renderer = rendererFactory?.CreateRenderer(this, renderLoop); - PlatformImpl.SetInputRoot(this); + impl.SetInputRoot(this); - PlatformImpl.Closed = HandleClosed; - PlatformImpl.Input = HandleInput; - PlatformImpl.Paint = HandlePaint; - PlatformImpl.Resized = HandleResized; - PlatformImpl.ScalingChanged = HandleScalingChanged; + impl.Closed = HandleClosed; + impl.Input = HandleInput; + impl.Paint = HandlePaint; + impl.Resized = HandleResized; + impl.ScalingChanged = HandleScalingChanged; _keyboardNavigationHandler?.SetOwner(this); @@ -110,7 +111,7 @@ namespace Avalonia.Controls this.GetObservable(PointerOverElementProperty) .Select( x => (x as InputElement)?.GetObservable(CursorProperty) ?? Observable.Empty()) - .Switch().Subscribe(cursor => PlatformImpl.SetCursor(cursor?.PlatformCursor)); + .Switch().Subscribe(cursor => PlatformImpl?.SetCursor(cursor?.PlatformCursor)); if (_applicationLifecycle != null) { @@ -135,10 +136,8 @@ namespace Avalonia.Controls /// /// Gets the platform-specific window implementation. /// - public ITopLevelImpl PlatformImpl - { - get; - } + [CanBeNull] + public ITopLevelImpl PlatformImpl { get; private set; } /// /// Gets the renderer for the window. @@ -177,7 +176,7 @@ namespace Avalonia.Controls Size ILayoutRoot.MaxClientSize => Size.Infinity; /// - double ILayoutRoot.LayoutScaling => PlatformImpl.Scaling; + double ILayoutRoot.LayoutScaling => PlatformImpl?.Scaling ?? 1; IStyleHost IStyleHost.StylingParent { @@ -189,25 +188,27 @@ namespace Avalonia.Controls /// protected virtual IRenderTarget CreateRenderTarget() { + if(PlatformImpl == null) + throw new InvalidOperationException("PlatformImpl isn't available"); return _renderInterface.CreateRenderTarget(PlatformImpl.Surfaces); } /// void IRenderRoot.Invalidate(Rect rect) { - PlatformImpl.Invalidate(rect); + PlatformImpl?.Invalidate(rect); } /// Point IRenderRoot.PointToClient(Point p) { - return PlatformImpl.PointToClient(p); + return PlatformImpl?.PointToClient(p) ?? default(Point); } /// Point IRenderRoot.PointToScreen(Point p) { - return PlatformImpl.PointToScreen(p); + return PlatformImpl?.PointToScreen(p) ?? default(Point); } /// @@ -224,6 +225,8 @@ namespace Avalonia.Controls /// protected virtual void HandleClosed() { + PlatformImpl = null; + Closed?.Invoke(this, EventArgs.Empty); Renderer?.Dispose(); Renderer = null; diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index 75587dcaec..32eaf499f0 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -12,6 +12,7 @@ using Avalonia.Platform; using Avalonia.Styling; using System.Collections.Generic; using System.Linq; +using JetBrains.Annotations; namespace Avalonia.Controls { @@ -87,11 +88,11 @@ namespace Avalonia.Controls static Window() { BackgroundProperty.OverrideDefaultValue(typeof(Window), Brushes.White); - TitleProperty.Changed.AddClassHandler((s, e) => s.PlatformImpl.SetTitle((string)e.NewValue)); + TitleProperty.Changed.AddClassHandler((s, e) => s.PlatformImpl?.SetTitle((string)e.NewValue)); HasSystemDecorationsProperty.Changed.AddClassHandler( - (s, e) => s.PlatformImpl.SetSystemDecorations((bool) e.NewValue)); + (s, e) => s.PlatformImpl?.SetSystemDecorations((bool) e.NewValue)); - IconProperty.Changed.AddClassHandler((s, e) => s.PlatformImpl.SetIcon(((WindowIcon)e.NewValue).PlatformImpl)); + IconProperty.Changed.AddClassHandler((s, e) => s.PlatformImpl?.SetIcon(((WindowIcon)e.NewValue).PlatformImpl)); } /// @@ -109,7 +110,7 @@ namespace Avalonia.Controls public Window(IWindowImpl impl) : base(impl) { - _maxPlatformClientSize = this.PlatformImpl.MaxClientSize; + _maxPlatformClientSize = PlatformImpl?.MaxClientSize ?? default(Size); } /// @@ -129,6 +130,7 @@ namespace Avalonia.Controls /// /// Gets the platform-specific window implementation. /// + [CanBeNull] public new IWindowImpl PlatformImpl => (IWindowImpl)base.PlatformImpl; /// @@ -164,8 +166,12 @@ namespace Avalonia.Controls /// public WindowState WindowState { - get { return this.PlatformImpl.WindowState; } - set { this.PlatformImpl.WindowState = value; } + get { return PlatformImpl?.WindowState ?? WindowState.Normal; } + set + { + if (PlatformImpl != null) + PlatformImpl.WindowState = value; + } } /// @@ -189,7 +195,7 @@ namespace Avalonia.Controls public void Close() { s_windows.Remove(this); - PlatformImpl.Dispose(); + PlatformImpl?.Dispose(); IsVisible = false; } @@ -221,7 +227,7 @@ namespace Avalonia.Controls { using (BeginAutoSizing()) { - PlatformImpl.Hide(); + PlatformImpl?.Hide(); } IsVisible = false; @@ -240,7 +246,7 @@ namespace Avalonia.Controls using (BeginAutoSizing()) { - PlatformImpl.Show(); + PlatformImpl?.Show(); } } @@ -278,7 +284,7 @@ namespace Avalonia.Controls var activated = affectedWindows.Where(w => w.IsActive).FirstOrDefault(); SetIsEnabled(affectedWindows, false); - var modal = PlatformImpl.ShowDialog(); + var modal = PlatformImpl?.ShowDialog(); var result = new TaskCompletionSource(); Observable.FromEventPattern( @@ -287,7 +293,7 @@ namespace Avalonia.Controls .Take(1) .Subscribe(_ => { - modal.Dispose(); + modal?.Dispose(); SetIsEnabled(affectedWindows, true); activated?.Activate(); result.SetResult((TResult)_dialogResult); diff --git a/src/Avalonia.Controls/WindowBase.cs b/src/Avalonia.Controls/WindowBase.cs index 21c248db0c..1f484fd6cb 100644 --- a/src/Avalonia.Controls/WindowBase.cs +++ b/src/Avalonia.Controls/WindowBase.cs @@ -9,6 +9,7 @@ using Avalonia.Controls.Primitives; using Avalonia.Input; using Avalonia.Layout; using Avalonia.Platform; +using JetBrains.Annotations; namespace Avalonia.Controls { @@ -43,10 +44,10 @@ namespace Avalonia.Controls public WindowBase(IWindowBaseImpl impl, IAvaloniaDependencyResolver dependencyResolver) : base(impl, dependencyResolver) { - PlatformImpl.Activated = HandleActivated; - PlatformImpl.Deactivated = HandleDeactivated; - PlatformImpl.PositionChanged = HandlePositionChanged; - this.GetObservable(ClientSizeProperty).Skip(1).Subscribe(x => PlatformImpl.Resize(x)); + impl.Activated = HandleActivated; + impl.Deactivated = HandleDeactivated; + impl.PositionChanged = HandlePositionChanged; + this.GetObservable(ClientSizeProperty).Skip(1).Subscribe(x => PlatformImpl?.Resize(x)); } /// @@ -64,6 +65,7 @@ namespace Avalonia.Controls /// public event EventHandler PositionChanged; + [CanBeNull] public new IWindowBaseImpl PlatformImpl => (IWindowBaseImpl) base.PlatformImpl; /// @@ -80,8 +82,12 @@ namespace Avalonia.Controls /// public Point Position { - get { return PlatformImpl.Position; } - set { PlatformImpl.Position = value; } + get { return PlatformImpl?.Position ?? default(Point); } + set + { + if (PlatformImpl is IWindowBaseImpl impl) + impl.Position = value; + } } /// @@ -98,7 +104,7 @@ namespace Avalonia.Controls /// public void Activate() { - PlatformImpl.Activate(); + PlatformImpl?.Activate(); } /// @@ -110,7 +116,7 @@ namespace Avalonia.Controls try { - PlatformImpl.Hide(); + PlatformImpl?.Hide(); IsVisible = false; } finally @@ -131,7 +137,7 @@ namespace Avalonia.Controls EnsureInitialized(); IsVisible = true; LayoutManager.Instance.ExecuteInitialLayoutPass(this); - PlatformImpl.Show(); + PlatformImpl?.Show(); } finally { @@ -163,10 +169,10 @@ namespace Avalonia.Controls { using (BeginAutoSizing()) { - PlatformImpl.Resize(finalSize); + PlatformImpl?.Resize(finalSize); } - return base.ArrangeOverride(PlatformImpl.ClientSize); + return base.ArrangeOverride(PlatformImpl?.ClientSize ?? default(Size)); } /// @@ -174,7 +180,7 @@ namespace Avalonia.Controls /// protected void EnsureInitialized() { - if (!this.IsInitialized) + if (!IsInitialized) { var init = (ISupportInitialize)this; init.BeginInit(); @@ -268,12 +274,12 @@ namespace Avalonia.Controls /// /// Starts moving a window with left button being held. Should be called from left mouse button press event handler /// - public void BeginMoveDrag() => PlatformImpl.BeginMoveDrag(); + public void BeginMoveDrag() => PlatformImpl?.BeginMoveDrag(); /// /// Starts resizing a window. This function is used if an application has window resizing controls. /// Should be called from left mouse button press event handler /// - public void BeginResizeDrag(WindowEdge edge) => PlatformImpl.BeginResizeDrag(edge); + public void BeginResizeDrag(WindowEdge edge) => PlatformImpl?.BeginResizeDrag(edge); } } diff --git a/src/Avalonia.DesignerSupport/DesignerAssist.cs b/src/Avalonia.DesignerSupport/DesignerAssist.cs index c9ae89354c..8d30f3cf25 100644 --- a/src/Avalonia.DesignerSupport/DesignerAssist.cs +++ b/src/Avalonia.DesignerSupport/DesignerAssist.cs @@ -75,7 +75,7 @@ namespace Avalonia.DesignerSupport private static void SetScalingFactor(double factor) { PlatformManager.SetDesignerScalingFactor(factor); - s_currentWindow?.PlatformImpl.Resize(s_currentWindow.ClientSize); + s_currentWindow?.PlatformImpl?.Resize(s_currentWindow.ClientSize); } static Window s_currentWindow; @@ -149,6 +149,8 @@ namespace Avalonia.DesignerSupport s_currentWindow = window; window.Show(); Design.ApplyDesignerProperties(window, control); + // ReSharper disable once PossibleNullReferenceException + // Always not null at this point Api.OnWindowCreated?.Invoke(window.PlatformImpl.Handle.Handle); Api.OnResize?.Invoke(); } diff --git a/src/Windows/Avalonia.Win32/Embedding/WinFormsAvaloniaControlHost.cs b/src/Windows/Avalonia.Win32/Embedding/WinFormsAvaloniaControlHost.cs index bdee85c91e..a484d6c0d2 100644 --- a/src/Windows/Avalonia.Win32/Embedding/WinFormsAvaloniaControlHost.cs +++ b/src/Windows/Avalonia.Win32/Embedding/WinFormsAvaloniaControlHost.cs @@ -15,7 +15,7 @@ namespace Avalonia.Win32.Embedding { private readonly EmbeddableControlRoot _root = new EmbeddableControlRoot(); - private IntPtr WindowHandle => ((WindowImpl) _root.PlatformImpl).Handle.Handle; + private IntPtr WindowHandle => ((WindowImpl) _root?.PlatformImpl)?.Handle?.Handle ?? IntPtr.Zero; public WinFormsAvaloniaControlHost() { @@ -25,6 +25,8 @@ namespace Avalonia.Win32.Embedding if (_root.IsFocused) FocusManager.Instance.Focus(null); _root.GotFocus += RootGotFocus; + // ReSharper disable once PossibleNullReferenceException + // Always non-null at this point _root.PlatformImpl.LostFocus += PlatformImpl_LostFocus; FixPosition(); } From 0b756d0b8a93a0c0073b226bd121e56d67fd96f2 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Fri, 26 May 2017 15:51:05 +0300 Subject: [PATCH 09/23] More null checks --- Avalonia.sln.DotSettings | 1 + src/Avalonia.Base/AvaloniaObject.cs | 11 +++----- .../Collections/AvaloniaDictionary.cs | 25 +++++++------------ src/Avalonia.Base/PriorityValue.cs | 2 +- src/Avalonia.Controls/Button.cs | 2 +- src/Avalonia.Controls/Control.cs | 2 +- src/Avalonia.Controls/ItemsControl.cs | 2 +- src/Avalonia.Controls/TextBox.cs | 7 ++++-- src/Avalonia.Controls/TopLevel.cs | 2 +- .../AppBuilder.cs | 8 +++++- src/Avalonia.Styling/Controls/NameScope.cs | 2 +- .../Rendering/ZIndexComparer.cs | 2 +- .../Avalonia.Cairo/Media/DrawingContext.cs | 1 + src/Gtk/Avalonia.Gtk3/SystemDialogs.cs | 1 + .../Parsers/SelectorParser.cs | 2 +- 15 files changed, 35 insertions(+), 35 deletions(-) diff --git a/Avalonia.sln.DotSettings b/Avalonia.sln.DotSettings index ab21d6e50b..1fd6f8d092 100644 --- a/Avalonia.sln.DotSettings +++ b/Avalonia.sln.DotSettings @@ -1,4 +1,5 @@  + ExplicitlyExcluded ExplicitlyExcluded ExplicitlyExcluded HINT diff --git a/src/Avalonia.Base/AvaloniaObject.cs b/src/Avalonia.Base/AvaloniaObject.cs index 1492c14c5f..1bdf1eb5e3 100644 --- a/src/Avalonia.Base/AvaloniaObject.cs +++ b/src/Avalonia.Base/AvaloniaObject.cs @@ -622,14 +622,9 @@ namespace Avalonia /// The default value. private object GetDefaultValue(AvaloniaProperty property) { - if (property.Inherits && _inheritanceParent != null) - { - return (_inheritanceParent as AvaloniaObject).GetValueInternal(property); - } - else - { - return ((IStyledPropertyAccessor)property).GetDefaultValue(GetType()); - } + if (property.Inherits && _inheritanceParent is AvaloniaObject aobj) + return aobj.GetValueInternal(property); + return ((IStyledPropertyAccessor) property).GetDefaultValue(GetType()); } /// diff --git a/src/Avalonia.Base/Collections/AvaloniaDictionary.cs b/src/Avalonia.Base/Collections/AvaloniaDictionary.cs index d63a5baf16..1aa239180c 100644 --- a/src/Avalonia.Base/Collections/AvaloniaDictionary.cs +++ b/src/Avalonia.Base/Collections/AvaloniaDictionary.cs @@ -103,11 +103,9 @@ namespace Avalonia.Collections _inner = new Dictionary(); - if (PropertyChanged != null) - { - PropertyChanged(this, new PropertyChangedEventArgs("Count")); - PropertyChanged(this, new PropertyChangedEventArgs($"Item[]")); - } + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Count")); + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs($"Item[]")); + if (CollectionChanged != null) { @@ -144,12 +142,9 @@ namespace Avalonia.Collections if (_inner.TryGetValue(key, out value)) { - if (PropertyChanged != null) - { - PropertyChanged(this, new PropertyChangedEventArgs("Count")); - PropertyChanged(this, new PropertyChangedEventArgs($"Item[{key}]")); - } - + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Count")); + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs($"Item[{key}]")); + if (CollectionChanged != null) { var e = new NotifyCollectionChangedEventArgs( @@ -199,11 +194,9 @@ namespace Avalonia.Collections private void NotifyAdd(TKey key, TValue value) { - if (PropertyChanged != null) - { - PropertyChanged(this, new PropertyChangedEventArgs("Count")); - PropertyChanged(this, new PropertyChangedEventArgs($"Item[{key}]")); - } + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Count")); + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs($"Item[{key}]")); + if (CollectionChanged != null) { diff --git a/src/Avalonia.Base/PriorityValue.cs b/src/Avalonia.Base/PriorityValue.cs index 21467f3962..c33d50ff0e 100644 --- a/src/Avalonia.Base/PriorityValue.cs +++ b/src/Avalonia.Base/PriorityValue.cs @@ -285,7 +285,7 @@ namespace Avalonia Property.Name, _valueType, value, - value.GetType()); + value?.GetType()); } } } diff --git a/src/Avalonia.Controls/Button.cs b/src/Avalonia.Controls/Button.cs index 24daa545ba..7ed1c7fd8c 100644 --- a/src/Avalonia.Controls/Button.cs +++ b/src/Avalonia.Controls/Button.cs @@ -275,7 +275,7 @@ namespace Avalonia.Controls { var button = e.Sender as Button; var isDefault = (bool)e.NewValue; - var inputRoot = button.VisualRoot as IInputElement; + var inputRoot = button?.VisualRoot as IInputElement; if (inputRoot != null) { diff --git a/src/Avalonia.Controls/Control.cs b/src/Avalonia.Controls/Control.cs index 516da813ef..fa0d8fe7d6 100644 --- a/src/Avalonia.Controls/Control.cs +++ b/src/Avalonia.Controls/Control.cs @@ -645,7 +645,7 @@ namespace Avalonia.Controls if (_focusAdorner != null) { - var adornerLayer = _focusAdorner.Parent as Panel; + var adornerLayer = (Panel)_focusAdorner.Parent; adornerLayer.Children.Remove(_focusAdorner); _focusAdorner = null; } diff --git a/src/Avalonia.Controls/ItemsControl.cs b/src/Avalonia.Controls/ItemsControl.cs index 5d12c9963f..aa209e0462 100644 --- a/src/Avalonia.Controls/ItemsControl.cs +++ b/src/Avalonia.Controls/ItemsControl.cs @@ -354,7 +354,7 @@ namespace Avalonia.Controls } var collection = sender as ICollection; - PseudoClasses.Set(":empty", collection.Count == 0); + PseudoClasses.Set(":empty", collection == null || collection.Count == 0); } /// diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index 9748e5e772..d2e8085d8c 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -720,7 +720,7 @@ namespace Avalonia.Controls if (pos < text.Length) { --pos; - if (pos > 0 && Text[pos - 1] == '\r' && Text[pos] == '\n') + if (pos > 0 && text[pos - 1] == '\r' && text[pos] == '\n') { --pos; } @@ -771,6 +771,9 @@ namespace Avalonia.Controls private string GetSelection() { + var text = Text; + if (string.IsNullOrEmpty(text)) + return ""; var selectionStart = SelectionStart; var selectionEnd = SelectionEnd; var start = Math.Min(selectionStart, selectionEnd); @@ -779,7 +782,7 @@ namespace Avalonia.Controls { return ""; } - return Text.Substring(start, end - start); + return text.Substring(start, end - start); } private int GetLine(int caretIndex, IList lines) diff --git a/src/Avalonia.Controls/TopLevel.cs b/src/Avalonia.Controls/TopLevel.cs index 53dd905eca..7e0f4b7ac1 100644 --- a/src/Avalonia.Controls/TopLevel.cs +++ b/src/Avalonia.Controls/TopLevel.cs @@ -106,7 +106,7 @@ namespace Avalonia.Controls _accessKeyHandler?.SetOwner(this); styler?.ApplyStyles(this); - ClientSize = PlatformImpl.ClientSize; + ClientSize = impl.ClientSize; this.GetObservable(PointerOverElementProperty) .Select( diff --git a/src/Avalonia.DotNetFrameworkRuntime/AppBuilder.cs b/src/Avalonia.DotNetFrameworkRuntime/AppBuilder.cs index fc7fdd2431..f8e8d4b094 100644 --- a/src/Avalonia.DotNetFrameworkRuntime/AppBuilder.cs +++ b/src/Avalonia.DotNetFrameworkRuntime/AppBuilder.cs @@ -82,7 +82,13 @@ namespace Avalonia private void LoadAssembliesInDirectory() { - foreach (var file in new FileInfo(Assembly.GetEntryAssembly().Location).Directory.EnumerateFiles("*.dll")) + var location = Assembly.GetEntryAssembly().Location; + if(location == null) + return; + var dir = new FileInfo(location).Directory; + if (dir == null) + return; + foreach (var file in dir.EnumerateFiles("*.dll")) { try { diff --git a/src/Avalonia.Styling/Controls/NameScope.cs b/src/Avalonia.Styling/Controls/NameScope.cs index 4c5875479e..8b5bd81d3c 100644 --- a/src/Avalonia.Styling/Controls/NameScope.cs +++ b/src/Avalonia.Styling/Controls/NameScope.cs @@ -50,7 +50,7 @@ namespace Avalonia.Controls return result; } - visual = (visual as ILogical).LogicalParent as Visual; + visual = (visual as ILogical)?.LogicalParent as Visual; } return null; diff --git a/src/Avalonia.Visuals/Rendering/ZIndexComparer.cs b/src/Avalonia.Visuals/Rendering/ZIndexComparer.cs index b9c43bcbc3..491541cd2e 100644 --- a/src/Avalonia.Visuals/Rendering/ZIndexComparer.cs +++ b/src/Avalonia.Visuals/Rendering/ZIndexComparer.cs @@ -8,6 +8,6 @@ namespace Avalonia.Rendering { public static readonly ZIndexComparer Instance = new ZIndexComparer(); - public int Compare(IVisual x, IVisual y) => x.ZIndex.CompareTo(y.ZIndex); + public int Compare(IVisual x, IVisual y) => (x?.ZIndex ?? 0).CompareTo(y?.ZIndex ?? 0); } } diff --git a/src/Gtk/Avalonia.Cairo/Media/DrawingContext.cs b/src/Gtk/Avalonia.Cairo/Media/DrawingContext.cs index 7d1776db0b..99b0a2ec73 100644 --- a/src/Gtk/Avalonia.Cairo/Media/DrawingContext.cs +++ b/src/Gtk/Avalonia.Cairo/Media/DrawingContext.cs @@ -9,6 +9,7 @@ using Avalonia.Cairo.Media.Imaging; using Avalonia.Media; using Avalonia.Platform; using Avalonia.Rendering; +// ReSharper disable PossibleNullReferenceException namespace Avalonia.Cairo.Media { diff --git a/src/Gtk/Avalonia.Gtk3/SystemDialogs.cs b/src/Gtk/Avalonia.Gtk3/SystemDialogs.cs index efdadc2379..f6232ac68e 100644 --- a/src/Gtk/Avalonia.Gtk3/SystemDialogs.cs +++ b/src/Gtk/Avalonia.Gtk3/SystemDialogs.cs @@ -28,6 +28,7 @@ namespace Avalonia.Gtk3 List disposables = null; Action dispose = () => { + // ReSharper disable once PossibleNullReferenceException foreach (var d in disposables) d.Dispose(); disposables.Clear(); diff --git a/src/Markup/Avalonia.Markup.Xaml/Parsers/SelectorParser.cs b/src/Markup/Avalonia.Markup.Xaml/Parsers/SelectorParser.cs index 8cf6f9794e..c4a7e188c6 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Parsers/SelectorParser.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Parsers/SelectorParser.cs @@ -68,7 +68,7 @@ namespace Avalonia.Markup.Xaml.Parsers } else if (property != null) { - var type = result.TargetType; + var type = result?.TargetType; if (type == null) { From 0ccd5fb3bead915f18a19fd3e8375e30bfda2444 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Fri, 26 May 2017 17:00:06 +0300 Subject: [PATCH 10/23] Speed limit enforced by aircraft --- build.cake | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/build.cake b/build.cake index 2f6bf5b0c1..00bc768b01 100644 --- a/build.cake +++ b/build.cake @@ -6,6 +6,7 @@ #addin "nuget:?package=NuGet.Core&version=2.12.0" #tool "nuget:https://dotnet.myget.org/F/nuget-build/?package=NuGet.CommandLine&version=4.3.0-preview1-3980&prerelease" #tool "nuget:?package=JetBrains.dotMemoryUnit&version=2.1.20150828.125449" +#tool "JetBrains.ReSharper.CommandLineTools" /////////////////////////////////////////////////////////////////////////////// // TOOLS /////////////////////////////////////////////////////////////////////////////// @@ -104,7 +105,7 @@ Task("Restore-NuGet-Packages") .Does(() => { var maxRetryCount = 5; - var toolTimeout = 1d; + var toolTimeout = 2d; Policy .Handle() .Retry(maxRetryCount, (exception, retryCount, context) => { @@ -287,6 +288,7 @@ Task("Zip-Files") Task("Create-NuGet-Packages") .IsDependentOn("Run-Unit-Tests") + .IsDependentOn("Inspect") .Does(() => { foreach(var nuspec in packages.NuspecNuGetSettings) @@ -363,6 +365,39 @@ Task("Publish-NuGet") Information("Publish-NuGet Task failed, but continuing with next Task..."); }); +Task("Inspect") + .WithCriteria(parameters.IsRunningOnWindows) + .IsDependentOn("Restore-NuGet-Packages") + .Does(() => + { + var badIssues = new []{"PossibleNullReferenceException"}; + var whitelist = new []{"tests\\", "src\\android", "src\\ios", + @"src\windows\avalonia.designer", @"src\avalonia.htmlrenderer\external"}; + Information("Running code inspections"); + + + StartProcess(@"tools\JetBrains.ReSharper.CommandLineTools\tools\inspectcode.exe", + new ProcessSettings{ Arguments = @"--output=artifacts\inspectcode.xml --profile=Avalonia.sln.DotSettings Avalonia.sln" }); + Information("Analyzing report"); + var doc = XDocument.Parse(System.IO.File.ReadAllText(@"artifacts\inspectcode.xml")); + var failBuild = false; + foreach(var xml in doc.Descendants("Issue")) + { + var typeId = xml.Attribute("TypeId").Value.ToString(); + if(badIssues.Contains(typeId)) + { + var file = xml.Attribute("File").Value.ToString().ToLower(); + if(whitelist.Any(wh => file.StartsWith(wh))) + continue; + var line = xml.Attribute("Line").Value.ToString(); + Error(typeId + " - " + file + " on line " + line); + failBuild = true; + } + } + if(failBuild) + throw new Exception("Issues found"); + }); + /////////////////////////////////////////////////////////////////////////////// // TARGETS /////////////////////////////////////////////////////////////////////////////// From 3d3786e7423c907db28ea94248c75beeb5085136 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Fri, 26 May 2017 17:36:53 +0300 Subject: [PATCH 11/23] Cake + Mono = HATE https://github.com/cake-build/cake/issues/1167 --- build.cake | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/build.cake b/build.cake index 00bc768b01..8cfdc3523a 100644 --- a/build.cake +++ b/build.cake @@ -371,15 +371,15 @@ Task("Inspect") .Does(() => { var badIssues = new []{"PossibleNullReferenceException"}; - var whitelist = new []{"tests\\", "src\\android", "src\\ios", - @"src\windows\avalonia.designer", @"src\avalonia.htmlrenderer\external"}; + var whitelist = new []{"tests", "src\\android", "src\\ios", + "src\\windows\\avalonia.designer", "src\\avalonia.htmlrenderer\\external"}; Information("Running code inspections"); - StartProcess(@"tools\JetBrains.ReSharper.CommandLineTools\tools\inspectcode.exe", - new ProcessSettings{ Arguments = @"--output=artifacts\inspectcode.xml --profile=Avalonia.sln.DotSettings Avalonia.sln" }); + StartProcess("tools\\JetBrains.ReSharper.CommandLineTools\\tools\\inspectcode.exe", + new ProcessSettings{ Arguments = "--output=artifacts\\inspectcode.xml --profile=Avalonia.sln.DotSettings Avalonia.sln" }); Information("Analyzing report"); - var doc = XDocument.Parse(System.IO.File.ReadAllText(@"artifacts\inspectcode.xml")); + var doc = XDocument.Parse(System.IO.File.ReadAllText("artifacts\\inspectcode.xml")); var failBuild = false; foreach(var xml in doc.Descendants("Issue")) { From b18a10383440bce406f1976ace26d42639038c20 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Sat, 27 May 2017 11:23:53 +0300 Subject: [PATCH 12/23] PR notes --- src/Avalonia.Controls/Control.cs | 2 +- src/Avalonia.Controls/TopLevel.cs | 2 +- src/Avalonia.DotNetFrameworkRuntime/AppBuilder.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Avalonia.Controls/Control.cs b/src/Avalonia.Controls/Control.cs index fa0d8fe7d6..27b046cf47 100644 --- a/src/Avalonia.Controls/Control.cs +++ b/src/Avalonia.Controls/Control.cs @@ -645,7 +645,7 @@ namespace Avalonia.Controls if (_focusAdorner != null) { - var adornerLayer = (Panel)_focusAdorner.Parent; + var adornerLayer = (IPanel)_focusAdorner.Parent; adornerLayer.Children.Remove(_focusAdorner); _focusAdorner = null; } diff --git a/src/Avalonia.Controls/TopLevel.cs b/src/Avalonia.Controls/TopLevel.cs index 7e0f4b7ac1..567ca80d6e 100644 --- a/src/Avalonia.Controls/TopLevel.cs +++ b/src/Avalonia.Controls/TopLevel.cs @@ -189,7 +189,7 @@ namespace Avalonia.Controls protected virtual IRenderTarget CreateRenderTarget() { if(PlatformImpl == null) - throw new InvalidOperationException("PlatformImpl isn't available"); + throw new InvalidOperationException("Cann't create render target, PlatformImpl is null (might be already disposed)"); return _renderInterface.CreateRenderTarget(PlatformImpl.Surfaces); } diff --git a/src/Avalonia.DotNetFrameworkRuntime/AppBuilder.cs b/src/Avalonia.DotNetFrameworkRuntime/AppBuilder.cs index f8e8d4b094..9a54cdbab0 100644 --- a/src/Avalonia.DotNetFrameworkRuntime/AppBuilder.cs +++ b/src/Avalonia.DotNetFrameworkRuntime/AppBuilder.cs @@ -83,7 +83,7 @@ namespace Avalonia private void LoadAssembliesInDirectory() { var location = Assembly.GetEntryAssembly().Location; - if(location == null) + if (string.IsNullOrWhiteSpace(location)) return; var dir = new FileInfo(location).Directory; if (dir == null) From 470e64fbe0cc1c979434a433888b82dc4715557f Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Sat, 27 May 2017 11:24:09 +0300 Subject: [PATCH 13/23] Added inspectcode.xml to artifact list --- appveyor.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/appveyor.yml b/appveyor.yml index 4bf7f7f157..6b63176a89 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -35,6 +35,7 @@ test: off artifacts: - path: artifacts\nuget\*.nupkg - path: artifacts\zip\*.zip + - path: artifacts\inspectcode.xml cache: - gtk-sharp-2.12.26.msi - dotnet-1.0.1.exe From 25ba0c8207ba050086e8ae8875def58f7836a9a0 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Sat, 27 May 2017 12:48:51 +0300 Subject: [PATCH 14/23] Updated dotMemory --- build.cake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.cake b/build.cake index 8cfdc3523a..c5d4c9a43e 100644 --- a/build.cake +++ b/build.cake @@ -5,7 +5,7 @@ #addin "nuget:?package=Polly&version=4.2.0" #addin "nuget:?package=NuGet.Core&version=2.12.0" #tool "nuget:https://dotnet.myget.org/F/nuget-build/?package=NuGet.CommandLine&version=4.3.0-preview1-3980&prerelease" -#tool "nuget:?package=JetBrains.dotMemoryUnit&version=2.1.20150828.125449" +#tool "nuget:?package=JetBrains.dotMemoryUnit&version=2.3.20160517.113140" #tool "JetBrains.ReSharper.CommandLineTools" /////////////////////////////////////////////////////////////////////////////// // TOOLS From a7ff93450e1fa527cda6aa26d2896be1432cb2bc Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Sat, 27 May 2017 14:05:44 +0200 Subject: [PATCH 15/23] Fixed problems with Windows.OpenWindows. - Showing a window was causing it to be added to the collection twice because `Show()` called `IsVisible = true` which called `Show()` - The window wasn't getting removed when the `PlatformImpl` signalled it was closed --- src/Avalonia.Controls/Window.cs | 11 +++ .../WindowTests.cs | 67 +++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index 32eaf499f0..39f9a8d272 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -238,6 +238,11 @@ namespace Avalonia.Controls /// public override void Show() { + if (IsVisible) + { + return; + } + s_windows.Add(this); EnsureInitialized(); @@ -272,6 +277,11 @@ namespace Avalonia.Controls /// public Task ShowDialog() { + if (IsVisible) + { + throw new InvalidOperationException("The window is already being shown."); + } + s_windows.Add(this); EnsureInitialized(); @@ -360,6 +370,7 @@ namespace Avalonia.Controls protected override void HandleClosed() { IsVisible = false; + s_windows.Remove(this); base.HandleClosed(); } diff --git a/tests/Avalonia.Controls.UnitTests/WindowTests.cs b/tests/Avalonia.Controls.UnitTests/WindowTests.cs index 96afecc966..d2b882310d 100644 --- a/tests/Avalonia.Controls.UnitTests/WindowTests.cs +++ b/tests/Avalonia.Controls.UnitTests/WindowTests.cs @@ -114,5 +114,72 @@ namespace Avalonia.Controls.UnitTests Assert.False(window.IsVisible); } } + + [Fact] + public void Show_Should_Add_Window_To_OpenWindows() + { + using (UnitTestApplication.Start(TestServices.StyledWindow)) + { + var window = new Window(); + + window.Show(); + + Assert.Equal(new[] { window }, Window.OpenWindows); + + window.Close(); + } + } + + [Fact] + public void Window_Should_Be_Added_To_OpenWindows_Only_Once() + { + using (UnitTestApplication.Start(TestServices.StyledWindow)) + { + var window = new Window(); + + window.Show(); + window.Show(); + window.IsVisible = true; + + Assert.Equal(new[] { window }, Window.OpenWindows); + + window.Close(); + } + } + + [Fact] + public void Close_Should_Remove_Window_From_OpenWindows() + { + using (UnitTestApplication.Start(TestServices.StyledWindow)) + { + var window = new Window(); + + window.Show(); + window.Close(); + + Assert.Empty(Window.OpenWindows); + } + } + + [Fact] + public void Impl_Closing_Should_Remove_Window_From_OpenWindows() + { + var windowImpl = new Mock(); + windowImpl.SetupProperty(x => x.Closed); + windowImpl.Setup(x => x.Scaling).Returns(1); + + var services = TestServices.StyledWindow.With( + windowingPlatform: new MockWindowingPlatform(() => windowImpl.Object)); + + using (UnitTestApplication.Start(services)) + { + var window = new Window(); + + window.Show(); + windowImpl.Object.Closed(); + + Assert.Empty(Window.OpenWindows); + } + } } } From 5a819c1c879c3d2669e4722f6a3e1120b56bfbb0 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Sat, 27 May 2017 16:50:05 +0200 Subject: [PATCH 16/23] Make Window.OpenWindows readonly And hack around the fact that it's static in unit tests. --- src/Avalonia.Controls/Window.cs | 4 ++-- tests/Avalonia.Controls.UnitTests/WindowTests.cs | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index 39f9a8d272..3802f2b6ea 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -47,12 +47,12 @@ namespace Avalonia.Controls /// public class Window : WindowBase, IStyleable, IFocusScope, ILayoutRoot, INameScope { - private static IList s_windows = new List(); + private static List s_windows = new List(); /// /// Retrieves an enumeration of all Windows in the currently running application. /// - public static IList OpenWindows => s_windows; + public static IReadOnlyList OpenWindows => s_windows; /// /// Defines the property. diff --git a/tests/Avalonia.Controls.UnitTests/WindowTests.cs b/tests/Avalonia.Controls.UnitTests/WindowTests.cs index d2b882310d..e0dd908bbb 100644 --- a/tests/Avalonia.Controls.UnitTests/WindowTests.cs +++ b/tests/Avalonia.Controls.UnitTests/WindowTests.cs @@ -4,6 +4,7 @@ // // ----------------------------------------------------------------------- +using System.Collections.Generic; using Avalonia.Platform; using Avalonia.UnitTests; using Moq; @@ -120,13 +121,12 @@ namespace Avalonia.Controls.UnitTests { using (UnitTestApplication.Start(TestServices.StyledWindow)) { + ClearOpenWindows(); var window = new Window(); window.Show(); Assert.Equal(new[] { window }, Window.OpenWindows); - - window.Close(); } } @@ -135,6 +135,7 @@ namespace Avalonia.Controls.UnitTests { using (UnitTestApplication.Start(TestServices.StyledWindow)) { + ClearOpenWindows(); var window = new Window(); window.Show(); @@ -152,6 +153,7 @@ namespace Avalonia.Controls.UnitTests { using (UnitTestApplication.Start(TestServices.StyledWindow)) { + ClearOpenWindows(); var window = new Window(); window.Show(); @@ -173,6 +175,7 @@ namespace Avalonia.Controls.UnitTests using (UnitTestApplication.Start(services)) { + ClearOpenWindows(); var window = new Window(); window.Show(); @@ -181,5 +184,12 @@ namespace Avalonia.Controls.UnitTests Assert.Empty(Window.OpenWindows); } } + + private void ClearOpenWindows() + { + // HACK: We really need a decent way to have "statics" that can be scoped to + // AvaloniaLocator scopes. + ((IList)Window.OpenWindows).Clear(); + } } } From 3c3dc973e1f8e59a6a0853ea0584c0d86a1c17f3 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Sat, 27 May 2017 23:50:49 +0200 Subject: [PATCH 17/23] Fix interop samples. They were missing a reference to System.Reactive. --- samples/interop/GtkInteropDemo/GtkInteropDemo.csproj | 5 +++++ samples/interop/WindowsInteropTest/WindowsInteropTest.csproj | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/samples/interop/GtkInteropDemo/GtkInteropDemo.csproj b/samples/interop/GtkInteropDemo/GtkInteropDemo.csproj index 044b96c865..0837a6efe5 100644 --- a/samples/interop/GtkInteropDemo/GtkInteropDemo.csproj +++ b/samples/interop/GtkInteropDemo/GtkInteropDemo.csproj @@ -149,6 +149,11 @@ ControlCatalog + + + 3.0.0 + + \ No newline at end of file diff --git a/samples/interop/WindowsInteropTest/WindowsInteropTest.csproj b/samples/interop/WindowsInteropTest/WindowsInteropTest.csproj index c787ab76ee..22b4e4188c 100644 --- a/samples/interop/WindowsInteropTest/WindowsInteropTest.csproj +++ b/samples/interop/WindowsInteropTest/WindowsInteropTest.csproj @@ -179,6 +179,11 @@ MSBuild:Compile + + + 3.0.0 + + \ No newline at end of file From 261df061e9befe7fc6d7f257a890e477219da744 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Sun, 28 May 2017 00:11:10 +0200 Subject: [PATCH 18/23] Reference Rx.props for interop samples. Instead of including the `PackageReference` directly in the csproj. --- samples/interop/GtkInteropDemo/GtkInteropDemo.csproj | 6 +----- .../interop/WindowsInteropTest/WindowsInteropTest.csproj | 6 +----- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/samples/interop/GtkInteropDemo/GtkInteropDemo.csproj b/samples/interop/GtkInteropDemo/GtkInteropDemo.csproj index 0837a6efe5..d9a61064f1 100644 --- a/samples/interop/GtkInteropDemo/GtkInteropDemo.csproj +++ b/samples/interop/GtkInteropDemo/GtkInteropDemo.csproj @@ -149,11 +149,7 @@ ControlCatalog - - - 3.0.0 - - + \ No newline at end of file diff --git a/samples/interop/WindowsInteropTest/WindowsInteropTest.csproj b/samples/interop/WindowsInteropTest/WindowsInteropTest.csproj index 22b4e4188c..28e5e274d0 100644 --- a/samples/interop/WindowsInteropTest/WindowsInteropTest.csproj +++ b/samples/interop/WindowsInteropTest/WindowsInteropTest.csproj @@ -179,11 +179,7 @@ MSBuild:Compile - - - 3.0.0 - - + \ No newline at end of file From 4730ee1c4125b9466f59ecfda7ec4bc6c6e7cb4c Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Tue, 30 May 2017 14:39:32 +0200 Subject: [PATCH 19/23] Fix spelling of descendant. While "descendent" is an acceptable English spelling, "descendant" is the common spelling. --- src/Avalonia.Controls/Control.cs | 2 +- .../Presenters/ScrollContentPresenter.cs | 4 +- .../Templates/TemplateExtensions.cs | 4 +- src/Avalonia.Controls/TopLevel.cs | 2 +- .../Navigation/DirectionalNavigation.cs | 46 +++++++++---------- .../Navigation/FocusExtensions.cs | 6 +-- .../Navigation/TabNavigation.cs | 46 +++++++++---------- src/Avalonia.Layout/Layoutable.cs | 2 +- .../LogicalTree/LogicalExtensions.cs | 6 +-- .../Styling/DescendentSelector.cs | 14 +++--- src/Avalonia.Styling/Styling/Selectors.cs | 6 +-- .../Rendering/ImmediateRenderer.cs | 2 +- src/Avalonia.Visuals/Visual.cs | 6 +-- .../VisualTree/VisualExtensions.cs | 16 +++---- .../Parsers/SelectorGrammar.cs | 10 ++-- .../Parsers/SelectorParser.cs | 6 +-- .../ListBoxTests.cs | 2 +- .../Presenters/ScrollContentPresenterTests.cs | 8 ++-- .../Primitives/PopupTests.cs | 2 +- .../Primitives/TemplatedControlTests.cs | 4 +- .../TreeViewTests.cs | 2 +- .../InteractiveTests.cs | 2 +- .../Avalonia.Layout.UnitTests/MeasureTests.cs | 2 +- .../Parsers/SelectorGrammarTests.cs | 4 +- .../SelectorTests_Descendent.cs | 26 +++++------ .../SelectorTests_Multiple.cs | 4 +- .../Avalonia.Visuals.UnitTests/VisualTests.cs | 2 +- 27 files changed, 118 insertions(+), 118 deletions(-) diff --git a/src/Avalonia.Controls/Control.cs b/src/Avalonia.Controls/Control.cs index 27b046cf47..758f7bbf55 100644 --- a/src/Avalonia.Controls/Control.cs +++ b/src/Avalonia.Controls/Control.cs @@ -469,7 +469,7 @@ namespace Avalonia.Controls { if (!IsInitialized) { - foreach (var i in this.GetSelfAndVisualDescendents()) + foreach (var i in this.GetSelfAndVisualDescendants()) { var c = i as IControl; diff --git a/src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs b/src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs index c217290226..e41c4e1e28 100644 --- a/src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs +++ b/src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs @@ -111,7 +111,7 @@ namespace Avalonia.Controls.Presenters /// The target visual. /// The portion of the target visual to bring into view. /// True if the scroll offset was changed; otherwise false. - public bool BringDescendentIntoView(IVisual target, Rect targetRect) + public bool BringDescendantIntoView(IVisual target, Rect targetRect) { if (Child == null) { @@ -262,7 +262,7 @@ namespace Avalonia.Controls.Presenters private void BringIntoViewRequested(object sender, RequestBringIntoViewEventArgs e) { - e.Handled = BringDescendentIntoView(e.TargetObject, e.TargetRect); + e.Handled = BringDescendantIntoView(e.TargetObject, e.TargetRect); } private void ChildChanged(AvaloniaPropertyChangedEventArgs e) diff --git a/src/Avalonia.Controls/Templates/TemplateExtensions.cs b/src/Avalonia.Controls/Templates/TemplateExtensions.cs index 535be23b23..09da737836 100644 --- a/src/Avalonia.Controls/Templates/TemplateExtensions.cs +++ b/src/Avalonia.Controls/Templates/TemplateExtensions.cs @@ -31,9 +31,9 @@ namespace Avalonia.Controls.Templates if (child.TemplatedParent != null) { - foreach (var descendent in GetTemplateChildren(child, templatedParent)) + foreach (var descendant in GetTemplateChildren(child, templatedParent)) { - yield return descendent; + yield return descendant; } } } diff --git a/src/Avalonia.Controls/TopLevel.cs b/src/Avalonia.Controls/TopLevel.cs index 567ca80d6e..1f1a29afa3 100644 --- a/src/Avalonia.Controls/TopLevel.cs +++ b/src/Avalonia.Controls/TopLevel.cs @@ -253,7 +253,7 @@ namespace Avalonia.Controls /// The window scaling. protected virtual void HandleScalingChanged(double scaling) { - foreach (ILayoutable control in this.GetSelfAndVisualDescendents()) + foreach (ILayoutable control in this.GetSelfAndVisualDescendants()) { control.InvalidateMeasure(); } diff --git a/src/Avalonia.Input/Navigation/DirectionalNavigation.cs b/src/Avalonia.Input/Navigation/DirectionalNavigation.cs index b2f7a35799..a88ed1e8aa 100644 --- a/src/Avalonia.Input/Navigation/DirectionalNavigation.cs +++ b/src/Avalonia.Input/Navigation/DirectionalNavigation.cs @@ -44,7 +44,7 @@ namespace Avalonia.Input.Navigation GetFirstInNextContainer(element, direction); case KeyboardNavigationMode.Cycle: return GetNextInContainer(element, container, direction) ?? - GetFocusableDescendent(container, direction); + GetFocusableDescendant(container, direction); case KeyboardNavigationMode.Contained: return GetNextInContainer(element, container, direction); default: @@ -53,7 +53,7 @@ namespace Avalonia.Input.Navigation } else { - return GetFocusableDescendents(element).FirstOrDefault(); + return GetFocusableDescendants(element).FirstOrDefault(); } } @@ -71,24 +71,24 @@ namespace Avalonia.Input.Navigation } /// - /// Gets the first or last focusable descendent of the specified element. + /// Gets the first or last focusable descendant of the specified element. /// /// The element. /// The direction to search. /// The element or null if not found.## - private static IInputElement GetFocusableDescendent(IInputElement container, NavigationDirection direction) + private static IInputElement GetFocusableDescendant(IInputElement container, NavigationDirection direction) { return IsForward(direction) ? - GetFocusableDescendents(container).FirstOrDefault() : - GetFocusableDescendents(container).LastOrDefault(); + GetFocusableDescendants(container).FirstOrDefault() : + GetFocusableDescendants(container).LastOrDefault(); } /// - /// Gets the focusable descendents of the specified element. + /// Gets the focusable descendants of the specified element. /// /// The element. - /// The element's focusable descendents. - private static IEnumerable GetFocusableDescendents(IInputElement element) + /// The element's focusable descendants. + private static IEnumerable GetFocusableDescendants(IInputElement element) { var children = element.GetVisualChildren().OfType(); @@ -99,11 +99,11 @@ namespace Avalonia.Input.Navigation yield return child; } - if (child.CanFocusDescendents()) + if (child.CanFocusDescendants()) { - foreach (var descendent in GetFocusableDescendents(child)) + foreach (var descendant in GetFocusableDescendants(child)) { - yield return descendent; + yield return descendant; } } } @@ -123,11 +123,11 @@ namespace Avalonia.Input.Navigation { if (direction == NavigationDirection.Down) { - var descendent = GetFocusableDescendents(element).FirstOrDefault(); + var descendant = GetFocusableDescendants(element).FirstOrDefault(); - if (descendent != null) + if (descendant != null) { - return descendent; + return descendant; } } @@ -156,11 +156,11 @@ namespace Avalonia.Input.Navigation if (element != null && direction == NavigationDirection.Up) { - var descendent = GetFocusableDescendents(element).LastOrDefault(); + var descendant = GetFocusableDescendants(element).LastOrDefault(); - if (descendent != null) + if (descendant != null) { - return descendent; + return descendant; } } @@ -193,7 +193,7 @@ namespace Avalonia.Input.Navigation var siblings = parent.GetVisualChildren() .OfType() - .Where(FocusExtensions.CanFocusDescendents); + .Where(FocusExtensions.CanFocusDescendants); var sibling = isForward ? siblings.SkipWhile(x => x != container).Skip(1).FirstOrDefault() : siblings.TakeWhile(x => x != container).LastOrDefault(); @@ -207,8 +207,8 @@ namespace Avalonia.Input.Navigation else { next = isForward ? - GetFocusableDescendents(sibling).FirstOrDefault() : - GetFocusableDescendents(sibling).LastOrDefault(); + GetFocusableDescendants(sibling).FirstOrDefault() : + GetFocusableDescendants(sibling).LastOrDefault(); } } @@ -220,8 +220,8 @@ namespace Avalonia.Input.Navigation else { next = isForward ? - GetFocusableDescendents(container).FirstOrDefault() : - GetFocusableDescendents(container).LastOrDefault(); + GetFocusableDescendants(container).FirstOrDefault() : + GetFocusableDescendants(container).LastOrDefault(); } return next; diff --git a/src/Avalonia.Input/Navigation/FocusExtensions.cs b/src/Avalonia.Input/Navigation/FocusExtensions.cs index 36fda1abb1..41e7c4cd7b 100644 --- a/src/Avalonia.Input/Navigation/FocusExtensions.cs +++ b/src/Avalonia.Input/Navigation/FocusExtensions.cs @@ -16,10 +16,10 @@ namespace Avalonia.Input.Navigation public static bool CanFocus(this IInputElement e) => e.Focusable && e.IsEnabledCore && e.IsVisible; /// - /// Checks if descendents of the specified element can be focused. + /// Checks if descendants of the specified element can be focused. /// /// The element. - /// True if descendents of the element can be focused. - public static bool CanFocusDescendents(this IInputElement e) => e.IsEnabledCore && e.IsVisible; + /// True if descendants of the element can be focused. + public static bool CanFocusDescendants(this IInputElement e) => e.IsEnabledCore && e.IsVisible; } } diff --git a/src/Avalonia.Input/Navigation/TabNavigation.cs b/src/Avalonia.Input/Navigation/TabNavigation.cs index bc3826d90e..6ba7ab1a0c 100644 --- a/src/Avalonia.Input/Navigation/TabNavigation.cs +++ b/src/Avalonia.Input/Navigation/TabNavigation.cs @@ -44,7 +44,7 @@ namespace Avalonia.Input.Navigation GetFirstInNextContainer(element, direction); case KeyboardNavigationMode.Cycle: return GetNextInContainer(element, container, direction) ?? - GetFocusableDescendent(container, direction); + GetFocusableDescendant(container, direction); case KeyboardNavigationMode.Contained: return GetNextInContainer(element, container, direction); default: @@ -53,29 +53,29 @@ namespace Avalonia.Input.Navigation } else { - return GetFocusableDescendents(element).FirstOrDefault(); + return GetFocusableDescendants(element).FirstOrDefault(); } } /// - /// Gets the first or last focusable descendent of the specified element. + /// Gets the first or last focusable descendant of the specified element. /// /// The element. /// The direction to search. /// The element or null if not found.## - private static IInputElement GetFocusableDescendent(IInputElement container, NavigationDirection direction) + private static IInputElement GetFocusableDescendant(IInputElement container, NavigationDirection direction) { return direction == NavigationDirection.Next ? - GetFocusableDescendents(container).FirstOrDefault() : - GetFocusableDescendents(container).LastOrDefault(); + GetFocusableDescendants(container).FirstOrDefault() : + GetFocusableDescendants(container).LastOrDefault(); } /// - /// Gets the focusable descendents of the specified element. + /// Gets the focusable descendants of the specified element. /// /// The element. - /// The element's focusable descendents. - private static IEnumerable GetFocusableDescendents(IInputElement element) + /// The element's focusable descendants. + private static IEnumerable GetFocusableDescendants(IInputElement element) { var mode = KeyboardNavigation.GetTabNavigation((InputElement)element); @@ -108,11 +108,11 @@ namespace Avalonia.Input.Navigation yield return child; } - if (child.CanFocusDescendents()) + if (child.CanFocusDescendants()) { - foreach (var descendent in GetFocusableDescendents(child)) + foreach (var descendant in GetFocusableDescendants(child)) { - yield return descendent; + yield return descendant; } } } @@ -132,11 +132,11 @@ namespace Avalonia.Input.Navigation { if (direction == NavigationDirection.Next) { - var descendent = GetFocusableDescendents(element).FirstOrDefault(); + var descendant = GetFocusableDescendants(element).FirstOrDefault(); - if (descendent != null) + if (descendant != null) { - return descendent; + return descendant; } } @@ -167,11 +167,11 @@ namespace Avalonia.Input.Navigation if (element != null && direction == NavigationDirection.Previous) { - var descendent = GetFocusableDescendents(element).LastOrDefault(); + var descendant = GetFocusableDescendants(element).LastOrDefault(); - if (descendent != null) + if (descendant != null) { - return descendent; + return descendant; } } @@ -203,7 +203,7 @@ namespace Avalonia.Input.Navigation var siblings = parent.GetVisualChildren() .OfType() - .Where(FocusExtensions.CanFocusDescendents); + .Where(FocusExtensions.CanFocusDescendants); var sibling = direction == NavigationDirection.Next ? siblings.SkipWhile(x => x != container).Skip(1).FirstOrDefault() : siblings.TakeWhile(x => x != container).LastOrDefault(); @@ -217,8 +217,8 @@ namespace Avalonia.Input.Navigation else { next = direction == NavigationDirection.Next ? - GetFocusableDescendents(sibling).FirstOrDefault() : - GetFocusableDescendents(sibling).LastOrDefault(); + GetFocusableDescendants(sibling).FirstOrDefault() : + GetFocusableDescendants(sibling).LastOrDefault(); } } @@ -230,8 +230,8 @@ namespace Avalonia.Input.Navigation else { next = direction == NavigationDirection.Next ? - GetFocusableDescendents(container).FirstOrDefault() : - GetFocusableDescendents(container).LastOrDefault(); + GetFocusableDescendants(container).FirstOrDefault() : + GetFocusableDescendants(container).LastOrDefault(); } return next; diff --git a/src/Avalonia.Layout/Layoutable.cs b/src/Avalonia.Layout/Layoutable.cs index 95a0dd625c..20050058bf 100644 --- a/src/Avalonia.Layout/Layoutable.cs +++ b/src/Avalonia.Layout/Layoutable.cs @@ -612,7 +612,7 @@ namespace Avalonia.Layout /// protected override sealed void OnVisualParentChanged(IVisual oldParent, IVisual newParent) { - foreach (ILayoutable i in this.GetSelfAndVisualDescendents()) + foreach (ILayoutable i in this.GetSelfAndVisualDescendants()) { i.InvalidateMeasure(); } diff --git a/src/Avalonia.Styling/LogicalTree/LogicalExtensions.cs b/src/Avalonia.Styling/LogicalTree/LogicalExtensions.cs index 0d9c0f6daa..a72a558258 100644 --- a/src/Avalonia.Styling/LogicalTree/LogicalExtensions.cs +++ b/src/Avalonia.Styling/LogicalTree/LogicalExtensions.cs @@ -37,15 +37,15 @@ namespace Avalonia.LogicalTree return logical.LogicalChildren; } - public static IEnumerable GetLogicalDescendents(this ILogical logical) + public static IEnumerable GetLogicalDescendants(this ILogical logical) { foreach (ILogical child in logical.LogicalChildren) { yield return child; - foreach (ILogical descendent in child.GetLogicalDescendents()) + foreach (ILogical descendant in child.GetLogicalDescendants()) { - yield return descendent; + yield return descendant; } } } diff --git a/src/Avalonia.Styling/Styling/DescendentSelector.cs b/src/Avalonia.Styling/Styling/DescendentSelector.cs index 525f31cbf1..943b3f0161 100644 --- a/src/Avalonia.Styling/Styling/DescendentSelector.cs +++ b/src/Avalonia.Styling/Styling/DescendentSelector.cs @@ -7,16 +7,16 @@ using Avalonia.LogicalTree; namespace Avalonia.Styling { - internal class DescendentSelector : Selector + internal class DescendantSelector : Selector { private readonly Selector _parent; private string _selectorString; - public DescendentSelector(Selector parent) + public DescendantSelector(Selector parent) { if (parent == null) { - throw new InvalidOperationException("Descendent selector must be preceeded by a selector."); + throw new InvalidOperationException("Descendant selector must be preceeded by a selector."); } _parent = parent; @@ -41,7 +41,7 @@ namespace Avalonia.Styling protected override SelectorMatch Evaluate(IStyleable control, bool subscribe) { ILogical c = (ILogical)control; - List> descendentMatches = new List>(); + List> descendantMatches = new List>(); while (c != null) { @@ -60,14 +60,14 @@ namespace Avalonia.Styling } else { - descendentMatches.Add(match.ObservableResult); + descendantMatches.Add(match.ObservableResult); } } } - if (descendentMatches.Count > 0) + if (descendantMatches.Count > 0) { - return new SelectorMatch(StyleActivator.Or(descendentMatches)); + return new SelectorMatch(StyleActivator.Or(descendantMatches)); } else { diff --git a/src/Avalonia.Styling/Styling/Selectors.cs b/src/Avalonia.Styling/Styling/Selectors.cs index 1b4c876f81..c91cc7af04 100644 --- a/src/Avalonia.Styling/Styling/Selectors.cs +++ b/src/Avalonia.Styling/Styling/Selectors.cs @@ -42,13 +42,13 @@ namespace Avalonia.Styling } /// - /// Returns a selector which matches a descendent of a previous selector. + /// Returns a selector which matches a descendant of a previous selector. /// /// The previous selector. /// The selector. - public static Selector Descendent(this Selector previous) + public static Selector Descendant(this Selector previous) { - return new DescendentSelector(previous); + return new DescendantSelector(previous); } /// diff --git a/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs b/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs index 4879532d6e..7d2222e449 100644 --- a/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs +++ b/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs @@ -164,7 +164,7 @@ namespace Avalonia.Rendering private static void ClearTransformedBounds(IVisual visual) { - foreach (var e in visual.GetSelfAndVisualDescendents()) + foreach (var e in visual.GetSelfAndVisualDescendants()) { BoundsTracker.SetTransformedBounds((Visual)visual, null); } diff --git a/src/Avalonia.Visuals/Visual.cs b/src/Avalonia.Visuals/Visual.cs index 20772d8f0d..cfe6bce7e0 100644 --- a/src/Avalonia.Visuals/Visual.cs +++ b/src/Avalonia.Visuals/Visual.cs @@ -314,7 +314,7 @@ namespace Avalonia /// /// Calls the method - /// for this control and all of its visual descendents. + /// for this control and all of its visual descendants. /// /// The event args. protected virtual void OnAttachedToVisualTreeCore(VisualTreeAttachmentEventArgs e) @@ -342,7 +342,7 @@ namespace Avalonia /// /// Calls the method - /// for this control and all of its visual descendents. + /// for this control and all of its visual descendants. /// /// The event args. protected virtual void OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) @@ -422,7 +422,7 @@ namespace Avalonia if (visual == null) { - throw new ArgumentException("'visual' is not a descendent of 'ancestor'."); + throw new ArgumentException("'visual' is not a descendant of 'ancestor'."); } } diff --git a/src/Avalonia.Visuals/VisualTree/VisualExtensions.cs b/src/Avalonia.Visuals/VisualTree/VisualExtensions.cs index 11fbae4321..289c4134d1 100644 --- a/src/Avalonia.Visuals/VisualTree/VisualExtensions.cs +++ b/src/Avalonia.Visuals/VisualTree/VisualExtensions.cs @@ -123,33 +123,33 @@ namespace Avalonia.VisualTree } /// - /// Enumerates the descendents of an in the visual tree. + /// Enumerates the descendants of an in the visual tree. /// /// The visual. /// The visual's ancestors. - public static IEnumerable GetVisualDescendents(this IVisual visual) + public static IEnumerable GetVisualDescendants(this IVisual visual) { foreach (IVisual child in visual.VisualChildren) { yield return child; - foreach (IVisual descendent in child.GetVisualDescendents()) + foreach (IVisual descendant in child.GetVisualDescendants()) { - yield return descendent; + yield return descendant; } } } /// - /// Enumerates an and its descendents in the visual tree. + /// Enumerates an and its descendants in the visual tree. /// /// The visual. /// The visual and its ancestors. - public static IEnumerable GetSelfAndVisualDescendents(this IVisual visual) + public static IEnumerable GetSelfAndVisualDescendants(this IVisual visual) { yield return visual; - foreach (var ancestor in visual.GetVisualDescendents()) + foreach (var ancestor in visual.GetVisualDescendants()) { yield return ancestor; } @@ -196,7 +196,7 @@ namespace Avalonia.VisualTree /// Tests whether an is an ancestor of another visual. /// /// The visual. - /// The potential descendent. + /// The potential descendant. /// /// True if is an ancestor of ; /// otherwise false. diff --git a/src/Markup/Avalonia.Markup.Xaml/Parsers/SelectorGrammar.cs b/src/Markup/Avalonia.Markup.Xaml/Parsers/SelectorGrammar.cs index d11df1a9e9..671fdfff30 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Parsers/SelectorGrammar.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Parsers/SelectorGrammar.cs @@ -93,9 +93,9 @@ namespace Avalonia.Markup.Xaml.Parsers public static readonly Parser Child = Parse.Char('>').Token().Return(new ChildSyntax()); - public static readonly Parser Descendent = + public static readonly Parser Descendant = from child in Parse.WhiteSpace.Many() - select new DescendentSyntax(); + select new DescendantSyntax(); public static readonly Parser Template = from template in Parse.String("/template/").Token() @@ -115,7 +115,7 @@ namespace Avalonia.Markup.Xaml.Parsers .Or(Property) .Or(Child) .Or(Template) - .Or(Descendent); + .Or(Descendant); public static readonly Parser> Selector = SingleSelector.Many().End(); @@ -191,11 +191,11 @@ namespace Avalonia.Markup.Xaml.Parsers } } - public class DescendentSyntax : ISyntax + public class DescendantSyntax : ISyntax { public override bool Equals(object obj) { - return obj is DescendentSyntax; + return obj is DescendantSyntax; } } diff --git a/src/Markup/Avalonia.Markup.Xaml/Parsers/SelectorParser.cs b/src/Markup/Avalonia.Markup.Xaml/Parsers/SelectorParser.cs index c4a7e188c6..1cecb21f17 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Parsers/SelectorParser.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Parsers/SelectorParser.cs @@ -47,7 +47,7 @@ namespace Avalonia.Markup.Xaml.Parsers var name = i as SelectorGrammar.NameSyntax; var property = i as SelectorGrammar.PropertySyntax; var child = i as SelectorGrammar.ChildSyntax; - var descendent = i as SelectorGrammar.DescendentSyntax; + var descendant = i as SelectorGrammar.DescendantSyntax; var template = i as SelectorGrammar.TemplateSyntax; if (ofType != null) @@ -102,9 +102,9 @@ namespace Avalonia.Markup.Xaml.Parsers { result = result.Child(); } - else if (descendent != null) + else if (descendant != null) { - result = result.Descendent(); + result = result.Descendant(); } else if (template != null) { diff --git a/tests/Avalonia.Controls.UnitTests/ListBoxTests.cs b/tests/Avalonia.Controls.UnitTests/ListBoxTests.cs index a588e88eb2..e58542bfb4 100644 --- a/tests/Avalonia.Controls.UnitTests/ListBoxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ListBoxTests.cs @@ -245,7 +245,7 @@ namespace Avalonia.Controls.UnitTests // The items were created before the template was applied, so now we need to go back // and re-arrange everything. - foreach (IControl i in target.GetSelfAndVisualDescendents()) + foreach (IControl i in target.GetSelfAndVisualDescendants()) { i.InvalidateMeasure(); } diff --git a/tests/Avalonia.Controls.UnitTests/Presenters/ScrollContentPresenterTests.cs b/tests/Avalonia.Controls.UnitTests/Presenters/ScrollContentPresenterTests.cs index 33ed26d6d8..ab16552e12 100644 --- a/tests/Avalonia.Controls.UnitTests/Presenters/ScrollContentPresenterTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Presenters/ScrollContentPresenterTests.cs @@ -219,7 +219,7 @@ namespace Avalonia.Controls.UnitTests.Presenters } [Fact] - public void BringDescendentIntoView_Should_Update_Offset() + public void BringDescendantIntoView_Should_Update_Offset() { var target = new ScrollContentPresenter { @@ -235,13 +235,13 @@ namespace Avalonia.Controls.UnitTests.Presenters target.UpdateChild(); target.Measure(Size.Infinity); target.Arrange(new Rect(0, 0, 100, 100)); - target.BringDescendentIntoView(target.Child, new Rect(200, 200, 0, 0)); + target.BringDescendantIntoView(target.Child, new Rect(200, 200, 0, 0)); Assert.Equal(new Vector(100, 100), target.Offset); } [Fact] - public void BringDescendentIntoView_Should_Handle_Child_Margin() + public void BringDescendantIntoView_Should_Handle_Child_Margin() { Border border; var target = new ScrollContentPresenter @@ -262,7 +262,7 @@ namespace Avalonia.Controls.UnitTests.Presenters target.UpdateChild(); target.Measure(Size.Infinity); target.Arrange(new Rect(0, 0, 100, 100)); - target.BringDescendentIntoView(border, new Rect(200, 200, 0, 0)); + target.BringDescendantIntoView(border, new Rect(200, 200, 0, 0)); Assert.Equal(new Vector(150, 150), target.Offset); } diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs index 367070b37a..f192e87f08 100644 --- a/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs @@ -222,7 +222,7 @@ namespace Avalonia.Controls.UnitTests.Primitives popup.Open(); var popupRoot = popup.PopupRoot; - var children = popupRoot.GetVisualDescendents().ToList(); + var children = popupRoot.GetVisualDescendants().ToList(); var types = children.Select(x => x.GetType().Name).ToList(); Assert.Equal( diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/TemplatedControlTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/TemplatedControlTests.cs index 3c2f2e4f5c..636492ed1c 100644 --- a/tests/Avalonia.Controls.UnitTests/Primitives/TemplatedControlTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Primitives/TemplatedControlTests.cs @@ -78,7 +78,7 @@ namespace Avalonia.Controls.UnitTests.Primitives target.ApplyTemplate(); - var types = target.GetVisualDescendents().Select(x => x.GetType()).ToList(); + var types = target.GetVisualDescendants().Select(x => x.GetType()).ToList(); Assert.Equal( new[] @@ -135,7 +135,7 @@ namespace Avalonia.Controls.UnitTests.Primitives target.ApplyTemplate(); - var templatedParents = target.GetVisualDescendents() + var templatedParents = target.GetVisualDescendants() .OfType() .Select(x => x.TemplatedParent) .ToList(); diff --git a/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs b/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs index eb0ee5a231..52d36a33fa 100644 --- a/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs +++ b/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs @@ -80,7 +80,7 @@ namespace Avalonia.Controls.UnitTests } [Fact] - public void Root_TreeContainerFromItem_Should_Return_Descendent_Item() + public void Root_TreeContainerFromItem_Should_Return_Descendant_Item() { var tree = CreateTestTreeData(); var target = new TreeView diff --git a/tests/Avalonia.Interactivity.UnitTests/InteractiveTests.cs b/tests/Avalonia.Interactivity.UnitTests/InteractiveTests.cs index dd0974fad0..067cf85c3c 100644 --- a/tests/Avalonia.Interactivity.UnitTests/InteractiveTests.cs +++ b/tests/Avalonia.Interactivity.UnitTests/InteractiveTests.cs @@ -391,7 +391,7 @@ namespace Avalonia.Interactivity.UnitTests if (handler != null) { - foreach (var i in tree.GetSelfAndVisualDescendents().Cast()) + foreach (var i in tree.GetSelfAndVisualDescendants().Cast()) { i.AddHandler(ev, handler, handlerRoutes, handledEventsToo); } diff --git a/tests/Avalonia.Layout.UnitTests/MeasureTests.cs b/tests/Avalonia.Layout.UnitTests/MeasureTests.cs index 570628b5b7..99983fd19b 100644 --- a/tests/Avalonia.Layout.UnitTests/MeasureTests.cs +++ b/tests/Avalonia.Layout.UnitTests/MeasureTests.cs @@ -45,7 +45,7 @@ namespace Avalonia.Layout.UnitTests } [Fact] - public void Removing_From_Parent_Should_Invalidate_Measure_Of_Control_And_Descendents() + public void Removing_From_Parent_Should_Invalidate_Measure_Of_Control_And_Descendants() { var panel = new StackPanel(); var child2 = new Border(); diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Parsers/SelectorGrammarTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Parsers/SelectorGrammarTests.cs index 676d6288d6..ad2c1bf8d3 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/Parsers/SelectorGrammarTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Parsers/SelectorGrammarTests.cs @@ -157,7 +157,7 @@ namespace Avalonia.Xaml.Base.UnitTest.Parsers } [Fact] - public void OfType_Descendent_Class() + public void OfType_Descendant_Class() { var result = SelectorGrammar.Selector.Parse("Button .foo").ToList(); @@ -165,7 +165,7 @@ namespace Avalonia.Xaml.Base.UnitTest.Parsers new SelectorGrammar.ISyntax[] { new SelectorGrammar.OfTypeSyntax { TypeName = "Button" }, - new SelectorGrammar.DescendentSyntax { }, + new SelectorGrammar.DescendantSyntax { }, new SelectorGrammar.ClassSyntax { Class = "foo" }, }, result); diff --git a/tests/Avalonia.Styling.UnitTests/SelectorTests_Descendent.cs b/tests/Avalonia.Styling.UnitTests/SelectorTests_Descendent.cs index 38491f9164..b4c284e7c9 100644 --- a/tests/Avalonia.Styling.UnitTests/SelectorTests_Descendent.cs +++ b/tests/Avalonia.Styling.UnitTests/SelectorTests_Descendent.cs @@ -14,23 +14,23 @@ using Xunit; namespace Avalonia.Styling.UnitTests { - public class SelectorTests_Descendent + public class SelectorTests_Descendant { [Fact] - public void Descendent_Matches_Control_When_It_Is_Child_OfType() + public void Descendant_Matches_Control_When_It_Is_Child_OfType() { var parent = new TestLogical1(); var child = new TestLogical2(); child.LogicalParent = parent; - var selector = default(Selector).OfType().Descendent().OfType(); + var selector = default(Selector).OfType().Descendant().OfType(); Assert.True(selector.Match(child).ImmediateResult); } [Fact] - public void Descendent_Matches_Control_When_It_Is_Descendent_OfType() + public void Descendant_Matches_Control_When_It_Is_Descendant_OfType() { var grandparent = new TestLogical1(); var parent = new TestLogical2(); @@ -39,13 +39,13 @@ namespace Avalonia.Styling.UnitTests parent.LogicalParent = grandparent; child.LogicalParent = parent; - var selector = default(Selector).OfType().Descendent().OfType(); + var selector = default(Selector).OfType().Descendant().OfType(); Assert.True(selector.Match(child).ImmediateResult); } [Fact] - public async Task Descendent_Matches_Control_When_It_Is_Descendent_OfType_And_Class() + public async Task Descendant_Matches_Control_When_It_Is_Descendant_OfType_And_Class() { var grandparent = new TestLogical1(); var parent = new TestLogical2(); @@ -55,14 +55,14 @@ namespace Avalonia.Styling.UnitTests parent.LogicalParent = grandparent; child.LogicalParent = parent; - var selector = default(Selector).OfType().Class("foo").Descendent().OfType(); + var selector = default(Selector).OfType().Class("foo").Descendant().OfType(); var activator = selector.Match(child).ObservableResult; Assert.True(await activator.Take(1)); } [Fact] - public async Task Descendent_Doesnt_Match_Control_When_It_Is_Descendent_OfType_But_Wrong_Class() + public async Task Descendant_Doesnt_Match_Control_When_It_Is_Descendant_OfType_But_Wrong_Class() { var grandparent = new TestLogical1(); var parent = new TestLogical2(); @@ -73,14 +73,14 @@ namespace Avalonia.Styling.UnitTests parent.Classes.Add("foo"); child.LogicalParent = parent; - var selector = default(Selector).OfType().Class("foo").Descendent().OfType(); + var selector = default(Selector).OfType().Class("foo").Descendant().OfType(); var activator = selector.Match(child).ObservableResult; Assert.False(await activator.Take(1)); } [Fact] - public async Task Descendent_Matches_Any_Ancestor() + public async Task Descendant_Matches_Any_Ancestor() { var grandparent = new TestLogical1(); var parent = new TestLogical1(); @@ -89,7 +89,7 @@ namespace Avalonia.Styling.UnitTests parent.LogicalParent = grandparent; child.LogicalParent = parent; - var selector = default(Selector).OfType().Class("foo").Descendent().OfType(); + var selector = default(Selector).OfType().Class("foo").Descendant().OfType(); var activator = selector.Match(child).ObservableResult; Assert.False(await activator.Take(1)); @@ -104,9 +104,9 @@ namespace Avalonia.Styling.UnitTests } [Fact] - public void Descendent_Selector_Should_Have_Correct_String_Representation() + public void Descendant_Selector_Should_Have_Correct_String_Representation() { - var selector = default(Selector).OfType().Class("foo").Descendent().OfType(); + var selector = default(Selector).OfType().Class("foo").Descendant().OfType(); Assert.Equal("TestLogical1.foo TestLogical3", selector.ToString()); } diff --git a/tests/Avalonia.Styling.UnitTests/SelectorTests_Multiple.cs b/tests/Avalonia.Styling.UnitTests/SelectorTests_Multiple.cs index 5a06734819..067b08b296 100644 --- a/tests/Avalonia.Styling.UnitTests/SelectorTests_Multiple.cs +++ b/tests/Avalonia.Styling.UnitTests/SelectorTests_Multiple.cs @@ -91,11 +91,11 @@ namespace Avalonia.Styling.UnitTests } [Fact] - public void TargetType_Descendent() + public void TargetType_Descendant() { var selector = default(Selector) .OfType