192 lines
7.5 KiB
C#
192 lines
7.5 KiB
C#
using System.Windows.Media.Animation;
|
||
using System.Windows.Threading;
|
||
|
||
namespace NeoUI.Controls;
|
||
|
||
/// <summary>
|
||
/// 代表一个通知视图,用于在应用程序中显示系统通知。此类继承自Window,并根据提供的Notification模型和位置信息来初始化自身。支持抽屉式滑入和滑出动画效果。
|
||
/// </summary>
|
||
public partial class NotificationView
|
||
{
|
||
private readonly DispatcherTimer? closeTimer;
|
||
private readonly NotificationPlacement placement; // 新增一个字段来存储位置
|
||
|
||
/// <summary>
|
||
/// 当通知视图加载完毕并准备好显示时触发的事件。此事件允许外部代码在通知视图完全初始化后执行特定操作,例如调整其位置或开始动画。
|
||
/// </summary>
|
||
public event Action<NotificationView>? Ready;
|
||
|
||
/// <summary>
|
||
/// 获取与此视图关联的通知模型。该模型包含了通知的标题、消息内容、类型以及显示时长等信息。
|
||
/// </summary>
|
||
public Notification Model { get; }
|
||
|
||
/// <summary>
|
||
/// 代表一个通知视图,用于在应用程序中显示系统通知。该类继承自Window,并根据提供的Notification模型和位置信息来初始化自身。
|
||
/// </summary>
|
||
public NotificationView(Notification model, NotificationPlacement placement) // 构造函数接收placement
|
||
{
|
||
InitializeComponent();
|
||
this.Model = model;
|
||
this.DataContext = this.Model;
|
||
this.placement = placement; // 保存placement
|
||
|
||
this.Opacity = 0; // 初始时依然保持透明,防止在动画开始前闪烁
|
||
this.Loaded += (_, _) => Ready?.Invoke(this);
|
||
|
||
if (model.Duration <= TimeSpan.Zero) return;
|
||
closeTimer = new DispatcherTimer { Interval = model.Duration };
|
||
closeTimer.Tick += (_, _) => AnimateOut();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 命令视图执行抽屉式滑入动画
|
||
/// </summary>
|
||
public void AnimateIn(double finalLeft, double finalTop)
|
||
{
|
||
// Manager已经计算好了最终位置,我们只需执行动画
|
||
this.Top = finalTop; // Y坐标直接设定
|
||
|
||
// 根据位置判断是从左侧滑入还是右侧滑入
|
||
var isRightSide = placement == NotificationPlacement.TopRight ||
|
||
placement == NotificationPlacement.BottomRight;
|
||
var startLeft = isRightSide
|
||
? finalLeft + this.ActualWidth + 10 // 从右侧屏幕外开始
|
||
: finalLeft - this.ActualWidth - 10; // 从左侧屏幕外开始
|
||
|
||
// 在动画开始前,立即将窗口移动到屏幕外的起始位置
|
||
this.Left = startLeft;
|
||
|
||
// 创建滑入动画
|
||
var slideAnim = new DoubleAnimation(startLeft, finalLeft, TimeSpan.FromMilliseconds(400))
|
||
{
|
||
EasingFunction = new CubicEase { EasingMode = EasingMode.EaseOut }
|
||
};
|
||
|
||
// 同时,让窗口从透明变为不透明,这是一个很好的辅助效果
|
||
var fadeAnim = new DoubleAnimation(0, 1, TimeSpan.FromMilliseconds(200));
|
||
|
||
// 应用动画
|
||
this.BeginAnimation(Window.LeftProperty, slideAnim);
|
||
this.BeginAnimation(Window.OpacityProperty, fadeAnim);
|
||
|
||
closeTimer?.Start();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 命令视图执行抽屉式滑出动画
|
||
/// </summary>
|
||
public void AnimateOut()
|
||
{
|
||
closeTimer?.Stop();
|
||
|
||
// 计算滑出到屏幕外的目标位置
|
||
var isRightSide = placement is NotificationPlacement.TopRight or NotificationPlacement.BottomRight;
|
||
var endLeft = isRightSide ? this.Left + this.ActualWidth + 10 : this.Left - this.ActualWidth - 10;
|
||
|
||
// 创建滑出动画
|
||
var slideAnim = new DoubleAnimation(this.Left, endLeft, TimeSpan.FromMilliseconds(300))
|
||
{
|
||
EasingFunction = new CubicEase { EasingMode = EasingMode.EaseIn }
|
||
};
|
||
|
||
// 同时淡出
|
||
var fadeAnim = new DoubleAnimation(this.Opacity, 0, TimeSpan.FromMilliseconds(250));
|
||
|
||
// 当动画完成时,关闭窗口
|
||
slideAnim.Completed += (_, _) => this.Close();
|
||
|
||
this.BeginAnimation(Window.LeftProperty, slideAnim);
|
||
this.BeginAnimation(Window.OpacityProperty, fadeAnim);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 当其他通知关闭时,平滑地移动到新位置 (这个方法保持不变)
|
||
/// </summary>
|
||
public void AnimateMove(double newTop)
|
||
{
|
||
var moveAnim = new DoubleAnimation(this.Top, newTop, TimeSpan.FromMilliseconds(350))
|
||
{
|
||
EasingFunction = new CubicEase { EasingMode = EasingMode.EaseOut }
|
||
};
|
||
this.BeginAnimation(Window.TopProperty, moveAnim);
|
||
}
|
||
|
||
private void CloseButton_Click(object sender, RoutedEventArgs e)
|
||
{
|
||
AnimateOut();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 代表系统通知的模型,包含标题、消息内容、类型和显示时长等信息。此类用于在应用程序中创建并配置通知。
|
||
/// </summary>
|
||
public class Notification
|
||
{
|
||
/// <summary>
|
||
/// 获取此通知的唯一标识符。每个通知实例生成时都会自动分配一个全局唯一的ID。
|
||
/// </summary>
|
||
public Guid Id { get; } = Guid.NewGuid();
|
||
|
||
/// <summary>
|
||
/// 获取或设置通知的标题。此属性用于存储和显示通知的标题文本。
|
||
/// </summary>
|
||
public string Title { get; set; }
|
||
|
||
/// <summary>
|
||
/// 获取或设置通知的消息内容。此属性用于存储和显示通知的具体信息。
|
||
/// </summary>
|
||
public string Message { get; set; }
|
||
|
||
/// <summary>
|
||
/// 代表通知的类型,用于区分不同的通知类别,如信息、成功、警告或错误。
|
||
/// </summary>
|
||
public NotificationType Type { get; set; }
|
||
|
||
/// <summary>
|
||
/// 获取或设置通知显示的持续时间。此属性用于定义从通知显示到自动关闭的时间间隔。
|
||
/// </summary>
|
||
public TimeSpan Duration { get; set; }
|
||
|
||
/// <summary>
|
||
/// 代表系统通知的模型,包含标题、消息内容、类型和显示时长等信息。
|
||
/// </summary>
|
||
public Notification(string title, string message, NotificationType type, TimeSpan duration)
|
||
{
|
||
Title = title;
|
||
Message = message;
|
||
Type = type;
|
||
Duration = duration;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 通知类型枚举,用于定义不同类型的系统通知。
|
||
/// </summary>
|
||
public enum NotificationType
|
||
{
|
||
/// <summary>
|
||
/// 表示通知类型为信息。此枚举成员用于标识那些传达一般信息或非关键性消息的通知。
|
||
/// 通常,使用这种类型的通知来向用户提供一般性的提示或更新,比如操作的状态、系统的一般信息等场景。
|
||
/// </summary>
|
||
Info,
|
||
|
||
/// <summary>
|
||
/// 表示通知类型为成功。此枚举成员用于标识那些传达操作已成功完成或达到预期结果的通知。
|
||
/// 通常,使用这种类型的通知来向用户反馈积极的结果,比如数据保存成功、操作执行无误等场景。
|
||
/// </summary>
|
||
Success,
|
||
|
||
/// <summary>
|
||
/// 表示通知类型为警告。此枚举成员用于标识那些传达需要注意或潜在问题的通知。
|
||
/// 通常,使用这种类型的通知来提醒用户存在一些需要注意的情况,比如输入数据格式不正确、即将进行的操作可能带来风险等场景。
|
||
/// </summary>
|
||
Warning,
|
||
|
||
/// <summary>
|
||
/// 表示通知类型为错误。此枚举成员用于标识那些传达操作失败或出现异常情况的通知。
|
||
/// 通常,使用这种类型的通知来向用户反馈负面的结果,比如无法连接到服务器、数据保存失败等场景。
|
||
/// </summary>
|
||
Error
|
||
}
|