溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

C#?Winform如何實(shí)現(xiàn)自定義漂亮的通知效果

發(fā)布時(shí)間:2022-08-29 16:50:51 來源:億速云 閱讀:183 作者:iii 欄目:開發(fā)技術(shù)

這篇“C# Winform如何實(shí)現(xiàn)自定義漂亮的通知效果”文章的知識點(diǎn)大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細(xì),步驟清晰,具有一定的借鑒價(jià)值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“C# Winform如何實(shí)現(xiàn)自定義漂亮的通知效果”文章吧。

優(yōu)化調(diào)整

下面是對源代碼的修改、優(yōu)化和調(diào)整:

  • 修改 lblMsg(Label) 的 AutoSize 為false,盡可能多占通知窗體區(qū)域,Anchor跟隨窗體變換,文字左側(cè)垂直居中,用于顯示可能更多的消息.

  • 設(shè)定action、timer1默認(rèn)值,Name、Opacity、StartPosition(Manual)在構(gòu)造函數(shù)中指定,這樣就不用每次創(chuàng)建通知窗體時(shí)進(jìn)行賦值了。ShowInTaskbar = false;通知窗體不在任務(wù)欄顯示。

  • 將原有代碼中定時(shí)器時(shí)間間隔調(diào)整到100毫秒,原設(shè)置為1,時(shí)間太短人眼看不出區(qū)別,白白浪費(fèi)計(jì)算。

  • ShowNotice()改為靜態(tài)方法,直接通過Form_Alert.ShowNotice(msg, msgType);調(diào)用顯示窗體,不用new創(chuàng)建對象再調(diào)用。

  • AlertFormNum靜態(tài)屬性設(shè)置最多顯示的通知數(shù)量,默認(rèn)盡可能多的占滿垂直屏幕,手動(dòng)設(shè)置數(shù)量不能低于1或超出屏幕。

  • ShowTime靜態(tài)屬性設(shè)置完全顯示后通知的顯示時(shí)間,單位毫秒;也可以擴(kuò)展?jié)u變顯示和消失的時(shí)間。

  • MoveEntry靜態(tài)屬性設(shè)置消息框是否水平移動(dòng)進(jìn)入,默認(rèn)true。通過設(shè)置初始的消息框位置,即可實(shí)現(xiàn)水平移動(dòng)進(jìn)入。

  • 實(shí)現(xiàn)消息框占滿后,新的消息框替換最近消失的通知的功能。原實(shí)現(xiàn)中最多只能顯示10個(gè)通知框,當(dāng)再多時(shí)不會顯示(丟失掉),只有騰出位置(通知消失后)才能顯示新的,現(xiàn)在已經(jīng)優(yōu)化為超出的通知框會替換掉舊通知,不會丟失。

// 設(shè)置通知的數(shù)量
Form_Alert.AlertFormNum = 5;
Form_Alert.MoveEntry = false;// 不水平移動(dòng)進(jìn)入
  • 調(diào)整下圖標(biāo)位置,垂直方向居中一些

  • 添加顯示時(shí)指定消息字體的參數(shù),有需要可直接修改顯示文字的字體。

/// <summary>
/// 設(shè)置完x、y之后執(zhí)行初始化啟動(dòng)。設(shè)置位置、消息類型、顯示、倒計(jì)時(shí)
/// </summary>
/// <param name="msg"></param>
/// <param name="msgType"></param>
/// <param name="msgFont">字體,默認(rèn)不指定即可</param>
private void InitStart(string msg, MsgType msgType, Font msgFont = null)
{
    // ...
}

調(diào)用并顯示自定義通知

新建項(xiàng)目NotificationCustom,完成通知框的調(diào)用顯示

Form_Alert.ShowNotice("這是一條成功的消息", MsgType.Success);

Form_Alert.ShowNotice("警告!警告的消息", MsgType.Warning);

Form_Alert.ShowNotice("發(fā)生了錯(cuò)誤,禁止!", MsgType.Error);

Form_Alert.ShowNotice("一條普通的信息記錄", MsgType.Info);

或者顯示時(shí)指定字體(下面為隨機(jī)字體)

Form_Alert.ShowNotice("這是一條成功的消息", MsgType.Success, new Font(FontFamily.Families[random.Next(0, FontFamily.Families.Length)], (float)(10.0+10.0*random.NextDouble())));

主要實(shí)現(xiàn)過程

  • 創(chuàng)建一個(gè)無邊框窗體Form_Alert,添加Label(lblMsg)顯示通知消息,添加一個(gè)表示關(guān)閉的圖片(PictureBox)。

  • 設(shè)置窗體StartPosition = FormStartPosition.Manual;,后面用于設(shè)置其初始位置為指定的屏幕右下角

  • 通過不同的背景顏色、不同的圖片(icon,PictureBox)代表不同的消息類型(MsgType)

  • 定時(shí)器中通過定時(shí)時(shí)間完成消息窗的顯示(透明度變化)、顯示一定時(shí)間、關(guān)閉(逐漸透明)整個(gè)流程:定義消息窗體不同的操作(NotificationFormAction),start表示開始顯示,顯示窗體并在定時(shí)器中處理透明、移入的顯示過程,完全顯示后改變操作狀態(tài)為wait;設(shè)置消息窗體顯示等待的時(shí)間,操作狀態(tài)變?yōu)閏lose,定時(shí)時(shí)間之后再次執(zhí)行定時(shí)器進(jìn)入close處理;close過程中定時(shí)器執(zhí)行變得透明、移出,完全透明后關(guān)閉定時(shí)器、關(guān)閉窗體。

  • 點(diǎn)擊關(guān)閉按鈕圖標(biāo),窗體狀態(tài)變?yōu)閏lose,定時(shí)時(shí)間改為close的間隔100

  • 每次定時(shí)器執(zhí)行函數(shù)的結(jié)尾記錄下次執(zhí)行的時(shí)間,用于判斷當(dāng)兩個(gè)窗體的狀態(tài)相同時(shí),剩余執(zhí)行時(shí)間為多少,判斷哪個(gè)窗體最先消失,用于完成后面的消息通知太多時(shí),新舊消息框的替換【不嚴(yán)謹(jǐn),尤其在逐漸的顯示和關(guān)閉過程中,有著多次的定時(shí)器循環(huán),如果想要完全嚴(yán)格,可以考慮計(jì)算消息窗體最終消失的時(shí)間(消息框的狀態(tài),循環(huán)執(zhí)行的剩余次數(shù),每次的間隔時(shí)間綜合計(jì)算)】

  • ShowNotice()靜態(tài)方法顯示消息框,直接傳遞要顯示的消息和消息類型即可,分為Success,Warning,Error,Info四類,通過指定的 AlertFormNum 消息框數(shù)量(或默認(rèn)數(shù)量),循環(huán)依次顯示消息框,并啟動(dòng)定時(shí)器處理消息框的窗體狀態(tài):漸變顯示(透明度)、顯示一定時(shí)間(ShowTime)、漸變消失。循環(huán)中通過Application.OpenForms[fname]獲取通知框窗體,如果沒有獲取到則創(chuàng)建新窗體,并執(zhí)行顯示,結(jié)束整個(gè)顯示處理;在循環(huán)中記錄已有窗體中最先消失的窗體;如果全部循環(huán)完,則說明所有數(shù)量的通知框都存在,則完成對最先消失的窗體的替換并顯示新的消息窗體。

代碼實(shí)現(xiàn)

修改后全部代碼不到200行,如下,主要部分已經(jīng)進(jìn)行注釋:

namespace CustomAlertBoxDemo
{
    public enum NotificationFormAction
    {
        start,
        wait,
        close
    }
    public enum MsgType
    {
        Success,
        Warning,
        Error,
        Info
    }
    public partial class Form_Alert : Form
    {
        /// <summary>
        /// 通知窗體的數(shù)量,默認(rèn)為垂直屏幕幾乎占滿的數(shù)量
        /// </summary>
        private static int alertFormNum = Screen.PrimaryScreen.WorkingArea.Height / (75 + 5); // 75為窗體高度,如果調(diào)整窗體高度,記得修改此處
        /// <summary>
        /// 通知窗體的數(shù)量,默認(rèn)為垂直屏幕幾乎占滿的數(shù)量,手動(dòng)修改的數(shù)量不能超出屏幕和低于1,否則設(shè)置無效
        /// </summary>
        public static int AlertFormNum
        {
            get => alertFormNum;
            set
            {
                if (value <= Screen.PrimaryScreen.WorkingArea.Height / (75 + 5) && value > 0)
                {
                    alertFormNum = value;
                }
            }
        }
        /// <summary>
        /// 自定義通知的顯示時(shí)間,單位為毫秒,默認(rèn)為3分鐘,之后開始消失。可根據(jù)需要修改
        /// </summary>
        public static int ShowTime { get; set; } = 3000;
        /// <summary>
        /// 是否移動(dòng)進(jìn)入,默認(rèn)true
        /// </summary>
        public static bool MoveEntry { get; set; } = true;
        /// <summary>
        /// 創(chuàng)建通知窗體
        /// </summary>
        /// <param name="name">窗體名稱,必須指定</param>
        public Form_Alert(string name)
        {
            InitializeComponent();
            Name = name;
            this.Opacity = 0.0;
            ShowInTaskbar = false;
            StartPosition = FormStartPosition.Manual;
        }
        private NotificationFormAction action = NotificationFormAction.start;
        /// <summary>
        /// 當(dāng)前消息框的標(biāo)準(zhǔn)位置
        /// </summary>
        private int x, y;
        private void timer1_Tick(object sender, EventArgs e)
        {
            switch (this.action)
            {
                case NotificationFormAction.wait:
                    timer1.Interval = ShowTime;
                    action = NotificationFormAction.close;
                    break;
                case NotificationFormAction.start:
                    this.timer1.Interval = 100;
                    this.Opacity += 0.1;
                    if (this.x < this.Location.X)
                    {
                        this.Left-=20; // 移動(dòng)快點(diǎn)
                    }
                    else
                    {
                        if (this.Opacity == 1.0)
                        {
                            action = NotificationFormAction.wait;
                        }
                    }
                    break;
                case NotificationFormAction.close:
                    timer1.Interval = 100;
                    this.Opacity -= 0.1;
                    this.Left -= 20;
                    if (base.Opacity == 0.0)
                    {
                        timer1.Stop();
                        base.Close();
                    }
                    break;
            }
            // tag記錄下次執(zhí)行的時(shí)間,用于后續(xù)的替換
            timer1.Tag = DateTime.Now.AddMilliseconds(timer1.Interval);
        }
        private void pictureBox2_Click(object sender, EventArgs e)
        {
            timer1.Interval = 100;
            action = NotificationFormAction.close;
        }
        /// <summary>
        /// 設(shè)置完x、y之后執(zhí)行初始化啟動(dòng)。設(shè)置位置、消息類型、顯示、倒計(jì)時(shí)
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="msgType"></param>
        private void InitStart(string msg, MsgType msgType)
        {
            //this.Location = new Point(frm.x, frm.y);
            this.Location = new Point(x + (MoveEntry?Width / 2:0), y);
            switch (msgType)
            {
                case MsgType.Success:
                    pictureBox1.Image = Resources.success;
                    BackColor = Color.SeaGreen;
                    break;
                case MsgType.Error:
                    pictureBox1.Image = Resources.error;
                    BackColor = Color.DarkRed;
                    break;
                case MsgType.Info:
                    pictureBox1.Image = Resources.info;
                    BackColor = Color.RoyalBlue;
                    break;
                case MsgType.Warning:
                    pictureBox1.Image = Resources.warning;
                    BackColor = Color.DarkOrange;
                    break;
            }
            lblMsg.Text = msg;
            Show();
            timer1.Start();
        }
        public static void ShowNotice(string msg, MsgType msgType)
        {
            Form_Alert willDisappearFrm = null;
            for (int i = 1; i < alertFormNum+1; i++)
            {
                string fname = "alert" + i.ToString();
                Form_Alert frm = (Form_Alert)Application.OpenForms[fname];
                if (frm == null)
                {
                    frm = new Form_Alert(fname);
                    frm.x = Screen.PrimaryScreen.WorkingArea.Width - frm.Width - 5;
                    frm.y = Screen.PrimaryScreen.WorkingArea.Height - frm.Height * i - 5 * i;
                    // 設(shè)置完x、y之后執(zhí)行初始化啟動(dòng)
                    frm.InitStart(msg, msgType);
                    return;
                }
                else
                {
                    if (willDisappearFrm == null)
                    {
                        willDisappearFrm = frm;
                    }
                    else
                    {
                        if (willDisappearFrm.action < frm.action)
                        {
                            willDisappearFrm = frm;
                        }
                        else if (willDisappearFrm.action == frm.action)
                        {
                            // 不考慮一次沒執(zhí)行的情況
                            if (willDisappearFrm.timer1.Tag!=null&& frm.timer1.Tag != null)
                            {
                                if (willDisappearFrm.timer1.Tag == null)
                                {
                                    willDisappearFrm = frm;
                                }
                                else if(frm.timer1.Tag != null)
                                {
                                    if ((DateTime)willDisappearFrm.timer1.Tag > (DateTime)frm.timer1.Tag)
                                    {
                                        willDisappearFrm = frm;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            // 當(dāng)前最早要消失的窗體willDisappearFrm被替換
            var newfrm = new Form_Alert(willDisappearFrm.Name);
            newfrm.x = Screen.PrimaryScreen.WorkingArea.Width - newfrm.Width - 5;
            newfrm.y = willDisappearFrm.Location.Y;
            // 必須立即替換name
            var totalNum = 0;
            foreach (Form form in Application.OpenForms)
            {
                if (form is Form_Alert)
                {
                    totalNum += 1;
                }
            }
            willDisappearFrm.Name = $"Form_Alert{totalNum + 1}";
            willDisappearFrm.pictureBox2_Click(null, null);
            // 設(shè)置完x、y之后執(zhí)行初始化啟動(dòng)
            newfrm.InitStart(msg, msgType);
        }
    }
}

以上就是關(guān)于“C# Winform如何實(shí)現(xiàn)自定義漂亮的通知效果”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對大家有幫助,若想了解更多相關(guān)的知識內(nèi)容,請關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI