2025-08-24 13:49:55 +08:00
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
|
using System.Windows.Media.Animation;
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-01-02 17:30:41 +08:00
|
|
|
|
namespace Melskin.Controls;
|
2025-08-24 13:49:55 +08:00
|
|
|
|
#region Internal Implementation
|
|
|
|
|
|
internal class ScreenHost : IToastHost
|
|
|
|
|
|
{
|
|
|
|
|
|
private readonly List<Window> toastWindows = [];
|
|
|
|
|
|
private readonly object obj = new();
|
|
|
|
|
|
private const double Spacing = 15;
|
|
|
|
|
|
|
|
|
|
|
|
public void AddToast(ToastControl toast)
|
|
|
|
|
|
{
|
|
|
|
|
|
//空出空间,显示阴影
|
|
|
|
|
|
toast.Margin = new Thickness(4);
|
|
|
|
|
|
var window = new Window
|
|
|
|
|
|
{
|
|
|
|
|
|
Content = toast,
|
|
|
|
|
|
WindowStyle = WindowStyle.None,
|
|
|
|
|
|
AllowsTransparency = true,
|
|
|
|
|
|
Background = Brushes.Transparent,
|
|
|
|
|
|
ShowInTaskbar = false,
|
|
|
|
|
|
Topmost = true,
|
|
|
|
|
|
Owner = null,
|
|
|
|
|
|
SizeToContent = SizeToContent.WidthAndHeight,
|
|
|
|
|
|
Left = -9999
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
window.Loaded += (_, _) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
lock (obj)
|
|
|
|
|
|
{
|
|
|
|
|
|
toastWindows.Add(window);
|
|
|
|
|
|
RepositionToasts();
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
window.Closed += (_, _) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
lock (obj)
|
|
|
|
|
|
{
|
|
|
|
|
|
toastWindows.Remove(window);
|
|
|
|
|
|
RepositionToasts();
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
window.Show();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void RemoveToast(ToastControl toast)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.Assert(toastWindows != null, nameof(toastWindows) + " != null");
|
|
|
|
|
|
var window = toastWindows.FirstOrDefault(w => Equals(w.Content, toast));
|
|
|
|
|
|
window?.Close();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void RepositionToasts()
|
|
|
|
|
|
{
|
|
|
|
|
|
var workArea = SystemParameters.WorkArea;
|
|
|
|
|
|
var currentTop = Spacing; // 从顶部开始,有间距。
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var window in toastWindows)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 将窗口水平居中。
|
|
|
|
|
|
var left = workArea.Left + (workArea.Width - window.ActualWidth) / 2;
|
|
|
|
|
|
|
|
|
|
|
|
var moveAnim = new DoubleAnimation(currentTop, TimeSpan.FromMilliseconds(350))
|
|
|
|
|
|
{ EasingFunction = new QuinticEase { EasingMode = EasingMode.EaseOut } };
|
|
|
|
|
|
|
|
|
|
|
|
window.Left = left; //直接设置水平位置。
|
|
|
|
|
|
window.BeginAnimation(Window.TopProperty, moveAnim); // Animate vertical position.
|
|
|
|
|
|
|
|
|
|
|
|
// 更新下一次 Toast 的顶部位置。
|
|
|
|
|
|
currentTop += window.ActualHeight + Spacing;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
#endregion
|