From 540bade45a0d4c31fbb0dcb6483e6b68c9355e5e Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 21 Jul 2023 15:00:53 +0200 Subject: [PATCH] Improve WinodwNotificationManager - Allow usage from XAML - Allow any Visual as Host, so it can be used inside UserControl for example - Allow adding style classes for NotificationCards --- .../WindowNotificationManager.cs | 78 +++++++++++++++---- 1 file changed, 61 insertions(+), 17 deletions(-) diff --git a/src/Avalonia.Controls/Notifications/WindowNotificationManager.cs b/src/Avalonia.Controls/Notifications/WindowNotificationManager.cs index 0b7a19707b..80931d1865 100644 --- a/src/Avalonia.Controls/Notifications/WindowNotificationManager.cs +++ b/src/Avalonia.Controls/Notifications/WindowNotificationManager.cs @@ -1,11 +1,10 @@ using System; using System.Collections; using System.Linq; -using Avalonia.Reactive; using System.Threading.Tasks; using Avalonia.Controls.Metadata; using Avalonia.Controls.Primitives; -using Avalonia.Rendering; +using Avalonia.Threading; using Avalonia.VisualTree; namespace Avalonia.Controls.Notifications @@ -18,6 +17,7 @@ namespace Avalonia.Controls.Notifications public class WindowNotificationManager : TemplatedControl, IManagedNotificationManager { private IList? _items; + private AdornerLayer? adornerLayer; /// /// Defines the property. @@ -50,17 +50,40 @@ namespace Avalonia.Controls.Notifications set { SetValue(MaxItemsProperty, value); } } + /// + /// Defines the property + /// + public static readonly DirectProperty HostProperty = + AvaloniaProperty.RegisterDirect( + nameof(Host), + o => o.Host, + (o, v) => o.Host = v); + + private Visual? _Host; + + /// + /// The Host that this NotificationManger should register to. If the Host is null, the Parent will be used. + /// + public Visual? Host + { + get { return _Host; } + set { SetAndRaise(HostProperty, ref _Host, value); } + } + /// /// Initializes a new instance of the class. /// - /// The window that will host the control. - public WindowNotificationManager(TopLevel? host) + /// The visual that will host the control. + public WindowNotificationManager(Visual? host) : this() { - if (host != null) - { - Install(host); - } + Host = host; + } + /// + /// Initializes a new instance of the class. + /// + public WindowNotificationManager() + { UpdatePseudoClasses(Position); } @@ -73,6 +96,8 @@ namespace Avalonia.Controls.Notifications /// protected override void OnApplyTemplate(TemplateAppliedEventArgs e) { + base.OnApplyTemplate(e); + var itemsControl = e.NameScope.Find("PART_Items"); _items = itemsControl?.Children; } @@ -120,12 +145,15 @@ namespace Avalonia.Controls.Notifications (sender as NotificationCard)?.Close(); }; - _items?.Add(notificationControl); - - if (_items?.OfType().Count(i => !i.IsClosing) > MaxItems) + Dispatcher.UIThread.Post(() => { - _items.OfType().First(i => !i.IsClosing).Close(); - } + _items?.Add(notificationControl); + + if (_items?.OfType().Count(i => !i.IsClosing) > MaxItems) + { + _items.OfType().First(i => !i.IsClosing).Close(); + } + }); if (expiration == TimeSpan.Zero) { @@ -145,16 +173,32 @@ namespace Avalonia.Controls.Notifications { UpdatePseudoClasses(change.GetNewValue()); } + + if (change.Property == HostProperty) + { + Install(); + } } /// /// Installs the within the - /// of the host . /// - /// The that will be the host. - private void Install(TemplatedControl host) + private void Install() { - var adornerLayer = host.FindDescendantOfType()?.AdornerLayer; + // unregister from AdornerLayer if this control was already installed + if (adornerLayer is not null && !adornerLayer.Children.Contains(this)) + { + adornerLayer.Children.Remove(this); + } + + // Try to get the host. If host was null, use the TopLevel instead. + var host = Host ?? Parent as Visual; + + if (host is null) throw new InvalidOperationException("NotificationControl cannot be installed. Host was not found."); + + adornerLayer = host is TopLevel + ? host.FindDescendantOfType()?.AdornerLayer + : AdornerLayer.GetAdornerLayer(host); if (adornerLayer is not null) {