using System.Diagnostics; using System.Windows.Media.Animation; namespace Melskin.Controls; #region Internal Implementation internal class ScreenHost : IToastHost { private readonly List 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