Browse Source

begin port of notification controls

pull/2453/head
Dan Walmsley 8 years ago
parent
commit
b31701d1ca
  1. 9
      src/Avalonia.Controls/Notifications/INotificationManager.cs
  2. 101
      src/Avalonia.Controls/Notifications/Notification.cs
  3. 106
      src/Avalonia.Controls/Notifications/NotificationArea.cs
  4. 56
      src/Avalonia.Controls/Notifications/NotificationManager.cs

9
src/Avalonia.Controls/Notifications/INotificationManager.cs

@ -0,0 +1,9 @@
using System;
namespace Avalonia.Controls.Notifications
{
interface INotificationManager
{
void Show(object content, string areaName = "", TimeSpan? expirationTime = null, Action onClick = null, Action onClose = null);
}
}

101
src/Avalonia.Controls/Notifications/Notification.cs

@ -0,0 +1,101 @@
using System;
using System.Threading.Tasks;
using Avalonia.Controls.Primitives;
using Avalonia.Interactivity;
namespace Avalonia.Controls.Notifications
{
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));
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<Notification>(button);
notification?.Close();
};
}
}
protected override void OnTemplateApplied(TemplateAppliedEventArgs e)
{
base.OnTemplateApplied(e);
var closeButton = this.FindControl<Button>("PART_CloseButton");
if (closeButton != null)
closeButton.Click += OnCloseButtonOnClick;
//var storyboards = Template.Triggers.OfType<EventTrigger>().FirstOrDefault(t => t.RoutedEvent == NotificationCloseInvokedEvent)?.Actions.OfType<BeginStoryboard>().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();
}
public async void Close()
{
if (IsClosing)
{
return;
}
IsClosing = true;
RaiseEvent(new RoutedEventArgs(NotificationCloseInvokedEvent));
await Task.Delay(_closingAnimationTime);
RaiseEvent(new RoutedEventArgs(NotificationClosedEvent));
}
}
}

106
src/Avalonia.Controls/Notifications/NotificationArea.cs

@ -0,0 +1,106 @@
using System;
using System.Collections;
using Avalonia.Controls.Primitives;
using Avalonia.Interactivity;
namespace Avalonia.Controls.Notifications
{
public class NotificationArea : TemplatedControl
{
private IList _items;
public NotificationPosition Position
{
get { return (NotificationPosition)GetValue(PositionProperty); }
set { SetValue(PositionProperty, value); }
}
public static readonly AvaloniaProperty PositionProperty =
AvaloniaProperty.Register<NotificationArea, NotificationPosition>(nameof(Position), NotificationPosition.BottomRight);
public int MaxItems
{
get { return (int)GetValue(MaxItemsProperty); }
set { SetValue(MaxItemsProperty, value); }
}
public static readonly AvaloniaProperty MaxItemsProperty =
AvaloniaProperty.Register<NotificationArea, int>(nameof(MaxItems), int.MaxValue);
public NotificationArea()
{
NotificationManager.AddArea(this);
}
protected override void OnTemplateApplied(TemplateAppliedEventArgs e)
{
base.OnTemplateApplied(e);
var itemsControl = this.FindControl<Panel>("PART_Items");
_items = itemsControl?.Children;
}
public async void Show(object content, TimeSpan expirationTime, Action onClick, Action onClose)
{
var notification = new Notification
{
Content = content
};
notification.PointerPressed += (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<Notification>().Count(i => !i.IsClosing) > MaxItems)
{
_items.OfType<Notification>().First(i => !i.IsClosing).Close();
}
}
if (expirationTime == TimeSpan.MaxValue)
{
return;
}
await Task.Delay(expirationTime);
notification.Close();*/
}
private void OnNotificationClosed(object sender, RoutedEventArgs routedEventArgs)
{
var notification = sender as Notification;
_items.Remove(notification);
}
}
public enum NotificationPosition
{
TopLeft,
TopRight,
BottomLeft,
BottomRight
}
}

56
src/Avalonia.Controls/Notifications/NotificationManager.cs

@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Avalonia.Threading;
namespace Avalonia.Controls.Notifications
{
public class NotificationManager : INotificationManager
{
private static readonly List<NotificationArea> Areas = new List<NotificationArea>();
private static Window _window;
public NotificationManager()
{
}
public void Show(object content, string areaName = "", TimeSpan? expirationTime = null, Action onClick = null,
Action onClose = null)
{
if (!Dispatcher.UIThread.CheckAccess())
{
Dispatcher.UIThread.Post(
new Action(() => Show(content, areaName, expirationTime, onClick, onClose)));
return;
}
if (expirationTime == null)
expirationTime = TimeSpan.FromSeconds(5);
if (areaName == string.Empty && _window == null)
{
var workArea = Application.Current.MainWindow.Screens.Primary.WorkingArea;
_window = new Window
{
Position = workArea.Position,
Width = workArea.Width,
Height = workArea.Height
};
_window.Show();
}
foreach (var area in Areas.Where(a => a.Name == areaName))
{
area.Show(content, (TimeSpan)expirationTime, onClick, onClose);
}
}
internal static void AddArea(NotificationArea area)
{
Areas.Add(area);
}
}
}
Loading…
Cancel
Save