From 9468cb87a3a2aad2c1ba3c2ca2b31ccd28038fd2 Mon Sep 17 00:00:00 2001 From: Alexandre Heinen Date: Tue, 15 Dec 2020 11:20:16 -0300 Subject: [PATCH 1/2] Implementing the option to use multiple LifetimeSupervisors --- CONTRIBUTING.md | 54 +++++++++++++++++++ .../Display/NotificationsDisplaySupervisor.cs | 24 ++++++++- .../Display/NotificationsItemsControl.cs | 8 ++- .../Lifetime/CountBasedLifetimeSupervisor.cs | 14 +++++ .../INotificationsLifeTimeSupervisor.cs | 1 + .../TimeAndCountBasedLifetimeSupervisor.cs | 14 +++++ Src/ToastNotifications/Notifier.cs | 16 ++++++ 7 files changed, 129 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 150eb9f..979f1f0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,3 +4,57 @@ Any help, suggestions, finding issues, pull requests are really appreciated. If you crate an enhancement or bug fix to the library, and you would like to share it with the community, please send a pull request I will test, merge and release nuget + +Author: Alexandre José Heinen +Feature: Allowing multiple LifetimeSupervisors with different behaviors +I need to use two different LifetimeSupervisor, one with CountBasedLifetimeSupervisor and other with TimeAndCountBasedLifetimeSupervisor. If I create 2 separated Notifiers the notifications can be displayed over the notifications that are already opened. +For this I create a way to set multiple LifetimeSupervisors to same Notifiers and same DisplaySupervisor. +To work correctly the LifetimeSupervisors need to be cached, to pass the same instance. +Example of how to use: + +``` +private static Notifier GenerateNotifier(double notificationLifeTime, Corner notificationPosition) +{ + //here I check if the LifetimeSupervisor to use is based on time + //if it is null I create new instance + if (notificationLifeTime > 0 && _lifetimeTimeAndCount == null) + { + _lifetimeTimeAndCount = new TimeAndCountBasedLifetimeSupervisor( + notificationLifetime: TimeSpan.FromSeconds(notificationLifeTime), + maximumNotificationCount: MaximumNotificationCount.FromCount(5)); + } + + //here I check if the LifetimeSupervisor to use is based only on count + //if it is null I create new instance + if (notificationLifeTime == 0 && _lifetimeCount == null) + { + _lifetimeCount = new CountBasedLifetimeSupervisor(maximumNotificationCount: MaximumNotificationCount.FromCount(5)); + } + + //get the correct LifetimeSupervisor to use + INotificationsLifetimeSupervisor lifetimeSupervisor = notificationLifeTime > 0 ? (INotificationsLifetimeSupervisor)_lifetimeTimeAndCount : (INotificationsLifetimeSupervisor)_lifetimeCount; + + if (_notifier == null) + { + _notifier = new Notifier(cfg => + { + cfg.PositionProvider = new WindowPositionProvider( + parentWindow: Application.Current.MainWindow, + corner: notificationPosition, + offsetX: 10, + offsetY: 49); + + cfg.LifetimeSupervisor = lifetimeSupervisor; + + cfg.Dispatcher = Application.Current.Dispatcher; + }); + } + + //update the current LifetimeSupervisor in the notifier + _notifier.UpdateLifetimeSupervisor(lifetimeSupervisor); + + return _notifier; +} +``` + +In this case I'm not checking if the notificationLifeTime is different, but if you need you can cache into a dictionary with notificationLifeTime as the key. diff --git a/Src/ToastNotifications/Display/NotificationsDisplaySupervisor.cs b/Src/ToastNotifications/Display/NotificationsDisplaySupervisor.cs index e7117f3..6a6a52e 100644 --- a/Src/ToastNotifications/Display/NotificationsDisplaySupervisor.cs +++ b/Src/ToastNotifications/Display/NotificationsDisplaySupervisor.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Windows; using System.Windows.Threading; using ToastNotifications.Core; @@ -17,6 +18,7 @@ public class NotificationsDisplaySupervisor : IDisposable private readonly IKeyboardEventHandler _keyboardEventHandler; private INotificationsLifetimeSupervisor _lifetimeSupervisor; + private List _lifetimeSupervisorList; private NotificationsWindow _window; public NotificationsDisplaySupervisor(Dispatcher dispatcher, @@ -30,6 +32,7 @@ public NotificationsDisplaySupervisor(Dispatcher dispatcher, _lifetimeSupervisor = lifetimeSupervisor; _displayOptions = displayOptions; _keyboardEventHandler = keyboardEventHandler; + _lifetimeSupervisorList = new List(); _lifetimeSupervisor.ShowNotificationRequested += LifetimeSupervisorOnShowNotificationRequested; _lifetimeSupervisor.CloseNotificationRequested += LifetimeSupervisorOnCloseNotificationRequested; @@ -44,6 +47,17 @@ public void DisplayNotification(INotification notification) Dispatch(() => InternalDisplayNotification(notification)); } + public void UpdateLifetimeSupervisor(INotificationsLifetimeSupervisor lifetimeSupervisor) + { + if (!_lifetimeSupervisorList.Contains(lifetimeSupervisor)) + { + _lifetimeSupervisorList.Add(lifetimeSupervisor); + lifetimeSupervisor.ShowNotificationRequested += LifetimeSupervisorOnShowNotificationRequested; + lifetimeSupervisor.CloseNotificationRequested += LifetimeSupervisorOnCloseNotificationRequested; + } + _lifetimeSupervisor = lifetimeSupervisor; + } + private void InternalDisplayNotification(INotification notification) { InitializeWindow(); @@ -61,7 +75,15 @@ private void Close(INotification notification) private void InternalClose(INotification notification) { - _lifetimeSupervisor.CloseNotification(notification); + //Needs to iterate all lifetimeSupervisor to check on what the notification was opened + foreach (var lifetimeSupervisor in _lifetimeSupervisorList) + { + if (lifetimeSupervisor.ContainsNotification(notification)) + { + lifetimeSupervisor.CloseNotification(notification); + break; + } + } UpdateWindowPosition(); } diff --git a/Src/ToastNotifications/Display/NotificationsItemsControl.cs b/Src/ToastNotifications/Display/NotificationsItemsControl.cs index 834be9f..561c70f 100644 --- a/Src/ToastNotifications/Display/NotificationsItemsControl.cs +++ b/Src/ToastNotifications/Display/NotificationsItemsControl.cs @@ -110,7 +110,13 @@ private static T GetVisualChild(DependencyObject parent) where T : Visual public void AddNotification(NotificationDisplayPart notification) { - Items.Add(notification); + //Can't find why notifications are tried to add more than one time + //Without this condition an error was thrown + if (notification.Parent == null) + { + Items.Add(notification); + } + } public void RemoveNotification(NotificationDisplayPart notification) diff --git a/Src/ToastNotifications/Lifetime/CountBasedLifetimeSupervisor.cs b/Src/ToastNotifications/Lifetime/CountBasedLifetimeSupervisor.cs index 981feaa..eb42e94 100644 --- a/Src/ToastNotifications/Lifetime/CountBasedLifetimeSupervisor.cs +++ b/Src/ToastNotifications/Lifetime/CountBasedLifetimeSupervisor.cs @@ -83,6 +83,20 @@ public void ClearMessages(IClearStrategy clearStrategy) } } + public bool ContainsNotification(INotification notification) + { + var enumerator = _notifications.GetEnumerator(); + while (enumerator.MoveNext()) + { + if (enumerator.Current.Value.Notification == notification) + { + return true; + } + } + + return false; + } + public event EventHandler ShowNotificationRequested; public event EventHandler CloseNotificationRequested; } diff --git a/Src/ToastNotifications/Lifetime/INotificationsLifeTimeSupervisor.cs b/Src/ToastNotifications/Lifetime/INotificationsLifeTimeSupervisor.cs index adc9b6e..805906b 100644 --- a/Src/ToastNotifications/Lifetime/INotificationsLifeTimeSupervisor.cs +++ b/Src/ToastNotifications/Lifetime/INotificationsLifeTimeSupervisor.cs @@ -7,6 +7,7 @@ namespace ToastNotifications.Lifetime { public interface INotificationsLifetimeSupervisor : IDisposable { + bool ContainsNotification(INotification notification); void PushNotification(INotification notification); void CloseNotification(INotification notification); diff --git a/Src/ToastNotifications/Lifetime/TimeAndCountBasedLifetimeSupervisor.cs b/Src/ToastNotifications/Lifetime/TimeAndCountBasedLifetimeSupervisor.cs index 810f66a..4ad45fa 100644 --- a/Src/ToastNotifications/Lifetime/TimeAndCountBasedLifetimeSupervisor.cs +++ b/Src/ToastNotifications/Lifetime/TimeAndCountBasedLifetimeSupervisor.cs @@ -145,6 +145,20 @@ public void ClearMessages(IClearStrategy clearStrategy) } } + public bool ContainsNotification(INotification notification) + { + var enumerator = _notifications.GetEnumerator(); + while (enumerator.MoveNext()) + { + if (enumerator.Current.Value.Notification == notification) + { + return true; + } + } + + return false; + } + public event EventHandler ShowNotificationRequested; public event EventHandler CloseNotificationRequested; } diff --git a/Src/ToastNotifications/Notifier.cs b/Src/ToastNotifications/Notifier.cs index 25ad268..5b4262d 100644 --- a/Src/ToastNotifications/Notifier.cs +++ b/Src/ToastNotifications/Notifier.cs @@ -76,6 +76,22 @@ public void ClearMessages(IClearStrategy clearStrategy) _lifetimeSupervisor?.ClearMessages(clearStrategy); } + public void UpdateLifetimeSupervisor(INotificationsLifetimeSupervisor lifetimeSupervisor) + { + if (_configuration != null) + { + lock (_syncRoot) + { + _configuration.LifetimeSupervisor = lifetimeSupervisor; + _lifetimeSupervisor = lifetimeSupervisor; + _lifetimeSupervisor.UseDispatcher(_configuration.Dispatcher); + + _displaySupervisor.UpdateLifetimeSupervisor(_lifetimeSupervisor); + } + + } + } + private bool _disposed = false; public object SyncRoot => _syncRoot; From 48a8275d21613afd9764545ebdf254802e2af363 Mon Sep 17 00:00:00 2001 From: Alexandre Heinen Date: Tue, 15 Dec 2020 15:36:39 -0300 Subject: [PATCH 2/2] fix an error on close notification when it is only opened in a LifetimeSupervisor --- Src/ToastNotifications/Display/NotificationsDisplaySupervisor.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Src/ToastNotifications/Display/NotificationsDisplaySupervisor.cs b/Src/ToastNotifications/Display/NotificationsDisplaySupervisor.cs index 6a6a52e..e721234 100644 --- a/Src/ToastNotifications/Display/NotificationsDisplaySupervisor.cs +++ b/Src/ToastNotifications/Display/NotificationsDisplaySupervisor.cs @@ -33,6 +33,7 @@ public NotificationsDisplaySupervisor(Dispatcher dispatcher, _displayOptions = displayOptions; _keyboardEventHandler = keyboardEventHandler; _lifetimeSupervisorList = new List(); + _lifetimeSupervisorList.Add(lifetimeSupervisor); _lifetimeSupervisor.ShowNotificationRequested += LifetimeSupervisorOnShowNotificationRequested; _lifetimeSupervisor.CloseNotificationRequested += LifetimeSupervisorOnCloseNotificationRequested;