0

I have created NotificationForm to replace MessageBox, The notifications appear above each other, and wait 5 sec to disappear. Whenever a notification disappears the above ones go down to their new positions.

The only problem I got is when another thread creates a new notification, I got error of Cross-thread. I tried Invoke and HandleCreate and it didn't solve the problem.

Here is the code:

NotificationAlertForm

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using School.Properties;

namespace School.Forms
{
    public partial class NotificationAlert : Form
    {
        public enum enmAction
        {
            wait,
            start,
            close
        }

        public enum enmType
        {
            Success,
            Location,
            Error,
            Database
        }

        private static readonly List<NotificationAlert> activeAlerts = new List<NotificationAlert>();
        private enmAction action;
        private int x, y;

        public NotificationAlert()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            timer1.Interval = 1;
            action = enmAction.close;
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            switch (action)
            {
                case enmAction.wait:
                    timer1.Interval = 5000;
                    action = enmAction.close;
                    break;

                case enmAction.start:
                    timer1.Interval = 1;
                    Opacity += 0.1;
                    if (x < Location.X)
                    {
                        Left--;
                    }
                    else
                    {
                        if (Opacity == 1.0) action = enmAction.wait;
                    }

                    break;

                case enmAction.close:

                    var newY = 0;
                    // Remove the current alert from the list of active alerts
                    activeAlerts.Remove(this);

                    // Start a timer to gradually update the positions of the remaining alerts
                    var positionTimer = new Timer();
                    positionTimer.Interval = 250;
                    positionTimer.Tick += (ssender, args) =>
                    {
                        // Update the position of each remaining alert
                        var offset = 0;
                        foreach (var alert in activeAlerts)
                        {
                            alert.Invoke((Action)delegate ()
                            {
                                newY = Screen.PrimaryScreen.WorkingArea.Height - alert.Height * (offset + 1) -
                                       5 * offset;
                                if (alert.y != newY)
                                {
                                    // Update the y-coordinate of the alert gradually in small steps
                                    var step = Math.Sign(newY - alert.y) * 5;
                                    if (Math.Abs(newY - alert.y) < Math.Abs(step))
                                        alert.y = newY;
                                    else
                                        alert.y += step;
                                    alert.Location = new Point(alert.x, alert.y);
                                }

                                offset++;
                            });


                        }

                        // Stop the timer when all positions are updated
                        if (activeAlerts.Count == 0 || activeAlerts.All(a => a.y == newY)) positionTimer.Stop();
                    };
                    positionTimer.Start();

                    // Fade out and close the current alert
                    timer1.Interval = 1;
                    Opacity -= 0.1;
                    Left -= 3;
                    if (Opacity == 0.0) Close();
                    break;
            }
        }

        public void showAlert(string msg, enmType type)
        {
            // Add the new alert to the list of active alerts
            activeAlerts.Add(this);

            // Adjust the positions of all the active alerts
            var offset = 0;
            foreach (var alert in activeAlerts)
            {

                alert.y = Screen.PrimaryScreen.WorkingArea.Height - alert.Height * (offset + 1) - 5 * offset;
                if (!alert.IsHandleCreated)
                {
                    alert.CreateHandle();
                }
                alert.Invoke((Action)delegate ()
                {
                    alert.Location = new Point(alert.x, alert.y);
                    offset++;
                });
            }

            Opacity = 0.0;
            StartPosition = FormStartPosition.Manual;
            string fname;

            for (var i = 1; i < 10; i++)
            {
                fname = "alert" + i;
                var frm = (NotificationAlert)Application.OpenForms[fname];

                if (frm == null)
                {
                    Name = fname;
                    x = Screen.PrimaryScreen.WorkingArea.Width - Width + 15;
                    y = Screen.PrimaryScreen.WorkingArea.Height - Height * i - 5 * i;
                    Location = new Point(x, y);
                    break;
                }
            }

            x = Screen.PrimaryScreen.WorkingArea.Width - Width - 5;

            switch (type)
            {
                case enmType.Success:
                    pictureBox1.Image = Resources.icons8_ok_45px_1;
                    BackColor = Color.RoyalBlue;
                    break;

                case enmType.Error:
                    pictureBox1.Image = Resources.icons8_error_45px_1;
                    BackColor = Color.DarkRed;
                    break;

                case enmType.Database:
                    pictureBox1.Image = Resources.icons8_database_view_45px;
                    BackColor = Color.SeaGreen;
                    break;

                case enmType.Location:
                    pictureBox1.Image = Resources.icons8_location_45px;
                    BackColor = Color.OrangeRed;
                    break;
            }

            msg_text.Text = msg;
            TopMost = true;
            Show();
            action = enmAction.start;
            timer1.Interval = 1;
            timer1.Start();
        }
    }
}

NotificationAlertClass:

public static class NotificationAlertClass
    {
        public static void MessageSentSuccess(string msg)
        {
                var frm = new NotificationAlert();
                frm.showAlert(msg, NotificationAlert.enmType.Success);
        }

        public static void LocationSentSuccess(string msg)
        {
            var frm = new NotificationAlert();
            frm.showAlert(msg, NotificationAlert.enmType.Location);
        }

        public static void Error(string msg)
        {

            var frm = new NotificationAlert();
            frm.showAlert(msg, NotificationAlert.enmType.Error);
        }

        public static void DatabaseSuccess(string msg)
        {
           
                var frm = new NotificationAlert();
                frm.showAlert(msg, NotificationAlert.enmType.Database);
            
        }
    }

Tried MethodInvoke, it says that form handle must be created first, so I tried createHandle and still not works,

The only problem appears when another thread calls the class to start new Notificaiton

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129

0 Answers0