using System; using System.Linq; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Media; using System.Windows.Media.Animation; using Notifications.Wpf.Utils; namespace Notifications.Wpf.Controls { [TemplatePart(Name = "PART_CloseButton", Type = typeof(Button))] public class Notification : ContentControl { private TimeSpan _closingAnimationTime = TimeSpan.Zero; public bool IsClosing { get; set; } public static readonly RoutedEvent NotificationCloseInvokedEvent = EventManager.RegisterRoutedEvent( "NotificationCloseInvoked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(Notification)); public static readonly RoutedEvent NotificationClosedEvent = EventManager.RegisterRoutedEvent( "NotificationClosed", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(Notification)); static Notification() { DefaultStyleKeyProperty.OverrideMetadata(typeof(Notification), new FrameworkPropertyMetadata(typeof(Notification))); } public event RoutedEventHandler NotificationCloseInvoked { add { AddHandler(NotificationCloseInvokedEvent, value); } remove { RemoveHandler(NotificationCloseInvokedEvent, value); } } public event RoutedEventHandler NotificationClosed { add { AddHandler(NotificationClosedEvent, value); } remove { RemoveHandler(NotificationClosedEvent, value); } } public static bool GetCloseOnClick(DependencyObject obj) { return (bool)obj.GetValue(CloseOnClickProperty); } public static void SetCloseOnClick(DependencyObject obj, bool value) { obj.SetValue(CloseOnClickProperty, value); } public static readonly DependencyProperty CloseOnClickProperty = DependencyProperty.RegisterAttached("CloseOnClick", typeof(bool), typeof(Notification), new FrameworkPropertyMetadata(false,CloseOnClickChanged)); private static void CloseOnClickChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs) { var button = dependencyObject as Button; if (button == null) { return; } var value = (bool)dependencyPropertyChangedEventArgs.NewValue; if (value) { button.Click += (sender, args) => { var notification = VisualTreeHelperExtensions.GetParent(button); notification?.Close(); }; } } public override void OnApplyTemplate() { base.OnApplyTemplate(); var closeButton = GetTemplateChild("PART_CloseButton") as Button; if (closeButton != null) closeButton.Click += OnCloseButtonOnClick; var storyboards = Template.Triggers.OfType().FirstOrDefault(t => t.RoutedEvent == NotificationCloseInvokedEvent)?.Actions.OfType().Select(a => a.Storyboard); _closingAnimationTime = new TimeSpan(storyboards?.Max(s => Math.Min((s.Duration.HasTimeSpan ? s.Duration.TimeSpan + (s.BeginTime ?? TimeSpan.Zero) : TimeSpan.MaxValue).Ticks, s.Children.Select(ch => ch.Duration.TimeSpan + (s.BeginTime ?? TimeSpan.Zero)).Max().Ticks)) ?? 0); } private void OnCloseButtonOnClick(object sender, RoutedEventArgs args) { var button = sender as Button; if (button == null) return; button.Click -= OnCloseButtonOnClick; Close(); } //TODO: .NET40 public async void Close() { if (IsClosing) { return; } IsClosing = true; RaiseEvent(new RoutedEventArgs(NotificationCloseInvokedEvent)); await Task.Delay(_closingAnimationTime); RaiseEvent(new RoutedEventArgs(NotificationClosedEvent)); } } }