C# Winform实现Toast功能

public class Toast { public class ToastInfo { public Form Owner { get; set; } public string Text { get; set; } = ""; public bool Increase { get; set; } = true; public int StartTop { get; set; } = 20; public int Timeout { get; set; } = 2000; public Color BackColor { get; set; } = default; public Color TextColor { get; set; } = default; } [DllImport("Gdi32.dll", EntryPoint = "CreateRoundRectRgn")] public static extern IntPtr CreateRoundRectRgn ( int nLeftRect, // x-coordinate of upper-left corner int nTopRect, // y-coordinate of upper-left corner int nRightRect, // x-coordinate of lower-right corner int nBottomRect, // y-coordinate of lower-right corner int nWidthEllipse, // width of ellipse int nHeightEllipse // height of ellipse ); static object LockObject = new object(); public static void Show(ToastInfo toastInfo) { if (toastInfo.Owner == null) return; var toasts = toastInfo.Owner.Controls.Cast<Control>().Where(v => v?.GetType() == typeof(ToastControl)).ToList(); if (!toastInfo.Increase) { if (toasts.Count > 0) { var firstToast = toasts[0] as ToastControl; firstToast.timer1.Stop(); firstToast.ToastText = toastInfo.Text; firstToast.timer1.Start(); return; } } var toast = new ToastControl(); toast.Name = $"toast{toasts.Count}"; toast.ToastText = toastInfo.Text; toast.Top = (toasts.Count * (toast.Height + 5)) + toastInfo.StartTop; toast.Region = System.Drawing.Region.FromHrgn(CreateRoundRectRgn(0, 0, toast.Width, toast.Height, 5, 5)); if (toastInfo.BackColor != default) { toast.BackColor = toastInfo.BackColor; } if (toastInfo.TextColor != default) { toast.lblMsg.ForeColor = toastInfo.TextColor; } toastInfo.Owner.Controls.Add(toast); toast.timer1.Interval = toastInfo.Timeout; toast.timer1.Tag = toast; toast.timer1.Tick += new EventHandler((s, e) => { lock (LockObject) { var timer = (s as Timer); timer?.Stop(); var controlToast = timer.Tag as ToastControl; toastInfo.Owner?.Controls.Remove(controlToast); controlToast.Dispose(); var otherToasts = toastInfo.Owner.Controls.Cast<Control>().Where(v => v?.GetType() == typeof(ToastControl)).ToList(); for (int i = 0; i < otherToasts.Count; i++) { var toast2 = otherToasts[i]; toast2.Top -= (toast2.Height + 5); } } }); toast.timer1.Start(); toast.Left = (int)(toastInfo.Owner.Width / 2 - toast.Width / 2); toast.Visible = true; toast.BringToFront(); } public static void Info(string text, int timeOut = 2000, bool increase = true, int startTop = 20) { Show(new ToastInfo { Owner = Common.FindOwner(), Increase = increase, StartTop = startTop, Timeout = timeOut, Text = text, BackColor = ColorTranslator.FromHtml("#3C486B"), TextColor = Color.White }); } public static void Error(string text = "發生錯誤!", int timeOut = 2000, bool increase = true, int startTop = 20) { Logs.Write(text); Show(new ToastInfo { Owner = Common.FindOwner(), Increase = increase, StartTop = startTop, Timeout = timeOut, Text = text, BackColor = ColorTranslator.FromHtml("#FF6D60"), TextColor = Color.White }); } public static void Success(string text= "操作成功!", int timeOut = 2000, bool increase = true, int startTop = 20) { Show(new ToastInfo { Owner = Common.FindOwner(), Increase = increase, StartTop = startTop, Timeout = timeOut, Text = text, BackColor = ColorTranslator.FromHtml("#68B984"), TextColor = Color.White }); } }
注意的是:
lblMsg需要AutoSize=true;
自定義控件屬性:padding=10, 15, 10, 15 ;窗體代碼:
public string ToastText { get => lblMsg.Text; set => lblMsg.Text = value; } public ToastControl() { InitializeComponent(); this.Visible = false; lblMsg.SizeChanged += LblMsg_SizeChanged; } private void LblMsg_SizeChanged(object sender, EventArgs e) { if (lblMsg.Width > this.Width) { this.Width = this.Padding.Left + lblMsg.Width + this.Padding.Right; } else { lblMsg.Left = this.Width / 2 - lblMsg.Width / 2; } }
寻找上一层的窗口
public static Form FindOwner() { Form form = null; for (int i = 1; i <= 20; i++) { StackFrame stackFrame = new StackFrame(i); if (stackFrame.GetMethod() == null) { break; } if (stackFrame.GetMethod().DeclaringType.BaseType == typeof(Form)) { form = Application.OpenForms.Cast<Form>().Where(v => v.Name == stackFrame.GetMethod().DeclaringType.Name).FirstOrDefault(); if (form != null) { break; } } } if (form == null) { var frm = (Application.OpenForms[0] as Form)?.ActiveMdiChild; if (frm == null) { frm = Application.OpenForms[0]; } return frm; } return form; }
使用方式:
Toast.Error("一个错误的Toast!");

浙公网安备 33010602011771号