功能更新
This commit is contained in:
112
Melskin/Controls/Notification/Notification.cs
Normal file
112
Melskin/Controls/Notification/Notification.cs
Normal file
@@ -0,0 +1,112 @@
|
||||
namespace Melskin.Controls;
|
||||
|
||||
/// <summary>
|
||||
/// 通知管理器类,提供显示系统通知的方法。
|
||||
/// 该类主要用于在应用程序中方便地创建和显示不同类型的通知。
|
||||
/// </summary>
|
||||
public static class Notification
|
||||
{
|
||||
// 数据结构现在存储 Notification 模型,而不是 Window
|
||||
private static readonly Dictionary<NotificationPlacement, List<Tuple<NotificationModel, NotificationView>>> ActiveNotifications =
|
||||
new()
|
||||
{
|
||||
{ NotificationPlacement.TopRight, [] },
|
||||
{ NotificationPlacement.TopLeft, [] },
|
||||
{ NotificationPlacement.BottomRight, [] },
|
||||
{ NotificationPlacement.BottomLeft, [] }
|
||||
};
|
||||
|
||||
private static readonly object Lock = new();
|
||||
|
||||
/// <summary>
|
||||
/// 显示系统通知。
|
||||
/// </summary>
|
||||
/// <param name="title">通知的标题。</param>
|
||||
/// <param name="message">通知的内容消息。</param>
|
||||
/// <param name="type">通知的类型,默认为信息类型。</param>
|
||||
/// <param name="placement">通知在屏幕上的位置,默认为右上角。</param>
|
||||
/// <param name="durationSeconds">通知显示的持续时间(秒),默认为5秒。</param>
|
||||
public static void Show(string title, string message, NotificationType type = NotificationType.Info,
|
||||
NotificationPlacement placement = NotificationPlacement.TopRight, int durationSeconds = 5)
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
var model = new NotificationModel(title, message, type, TimeSpan.FromSeconds(durationSeconds));
|
||||
|
||||
// 修改这里:在创建 view 时传入 placement
|
||||
var view = new NotificationView(model, placement);
|
||||
|
||||
// 后续代码完全不变
|
||||
view.Ready += (v) => OnNotificationReady(v, placement);
|
||||
view.Closed += (_, _) => OnNotificationClosed(view, placement);
|
||||
view.Show();
|
||||
});
|
||||
}
|
||||
|
||||
private static void OnNotificationReady(NotificationView view, NotificationPlacement placement)
|
||||
{
|
||||
lock (Lock)
|
||||
{
|
||||
ActiveNotifications[placement].Add(new Tuple<NotificationModel, NotificationView>(view.Model, view));
|
||||
Reposition(placement);
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnNotificationClosed(NotificationView view, NotificationPlacement placement)
|
||||
{
|
||||
lock (Lock)
|
||||
{
|
||||
var itemToRemove = ActiveNotifications[placement].FirstOrDefault(t => t.Item2 == view);
|
||||
if (itemToRemove != null)
|
||||
{
|
||||
ActiveNotifications[placement].Remove(itemToRemove);
|
||||
Reposition(placement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void Reposition(NotificationPlacement placement)
|
||||
{
|
||||
var notifications = ActiveNotifications[placement];
|
||||
if (!notifications.Any()) return;
|
||||
|
||||
var workArea = SystemParameters.WorkArea;
|
||||
double currentTop;
|
||||
var isTop = placement == NotificationPlacement.TopLeft || placement == NotificationPlacement.TopRight;
|
||||
|
||||
if (isTop)
|
||||
{
|
||||
currentTop = workArea.Top + 10;
|
||||
}
|
||||
else // Bottom
|
||||
{
|
||||
// 对于底部,我们需要先计算总高度
|
||||
var totalHeight = notifications.Sum(t => t.Item2.ActualHeight + 10);
|
||||
currentTop = workArea.Bottom - totalHeight;
|
||||
}
|
||||
|
||||
foreach (var tuple in notifications)
|
||||
{
|
||||
var view = tuple.Item2;
|
||||
|
||||
// 在 `Ready` 事件之后,ActualWidth/Height 已经是准确的了
|
||||
var finalLeft = (placement == NotificationPlacement.TopRight || placement == NotificationPlacement.BottomRight)
|
||||
? workArea.Right - view.ActualWidth - 10
|
||||
: workArea.Left + 10;
|
||||
|
||||
// 检查这个窗口是否是新来的(通过透明度判断)
|
||||
if (view.Opacity == 0)
|
||||
{
|
||||
// 如果是新的,命令它播放入场动画
|
||||
view.AnimateIn(finalLeft, currentTop);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果是已经存在的,命令它平滑移动到新位置
|
||||
view.AnimateMove(currentTop);
|
||||
}
|
||||
|
||||
currentTop += view.ActualHeight + 10; // 为下一个窗口计算Y坐标
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user