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 });
}
}
使用方式:
Toast.Error("一个错误的Toast!");
寻找上一层的窗口
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; }