using System; using System.Collections; using System.Linq; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Threading; namespace Notifications.Wpf.Controls { public class NotificationArea : Control { public NotificationPosition Position { get { return (NotificationPosition)GetValue(PositionProperty); } set { SetValue(PositionProperty, value); } } // Using a DependencyProperty as the backing store for Position. This enables animation, styling, binding, etc... public static readonly DependencyProperty PositionProperty = DependencyProperty.Register("Position", typeof(NotificationPosition), typeof(NotificationArea), new PropertyMetadata(NotificationPosition.BottomRight)); public int MaxItems { get { return (int)GetValue(MaxItemsProperty); } set { SetValue(MaxItemsProperty, value); } } public static readonly DependencyProperty MaxItemsProperty = DependencyProperty.Register("MaxItems", typeof(int), typeof(NotificationArea), new PropertyMetadata(int.MaxValue)); private IList _items; public NotificationArea() { NotificationManager.AddArea(this); } static NotificationArea() { DefaultStyleKeyProperty.OverrideMetadata(typeof(NotificationArea), new FrameworkPropertyMetadata(typeof(NotificationArea))); } public override void OnApplyTemplate() { base.OnApplyTemplate(); var itemsControl = GetTemplateChild("PART_Items") as Panel; _items = itemsControl?.Children; } #if NET40 public void Show(object content, TimeSpan expirationTime, Action onClick, Action onClose) #else public async void Show(object content, TimeSpan expirationTime, Action onClick, Action onClose) #endif { var notification = new Notification { Content = content }; notification.MouseLeftButtonDown += (sender, args) => { if (onClick != null) { onClick.Invoke(); (sender as Notification)?.Close(); } }; notification.NotificationClosed += (sender, args) => onClose?.Invoke(); notification.NotificationClosed += OnNotificationClosed; if (!IsLoaded) { return; } var w = Window.GetWindow(this); var x = PresentationSource.FromVisual(w); if (x == null) { return; } lock (_items) { _items.Add(notification); if (_items.OfType().Count(i => !i.IsClosing) > MaxItems) { _items.OfType().First(i => !i.IsClosing).Close(); } } #if NET40 DelayExecute(expirationTime, () => { #else if (expirationTime == TimeSpan.MaxValue) { return; } await Task.Delay(expirationTime); #endif notification.Close(); #if NET40 }); #endif } private void OnNotificationClosed(object sender, RoutedEventArgs routedEventArgs) { var notification = sender as Notification; _items.Remove(notification); } #if NET40 private static void DelayExecute(TimeSpan delay, Action actionToExecute) { if (actionToExecute != null) { var timer = new DispatcherTimer { Interval = delay }; timer.Tick += (sender, args) => { timer.Stop(); actionToExecute(); }; timer.Start(); } } #endif } public enum NotificationPosition { TopLeft, TopRight, BottomLeft, BottomRight } }