I'm creating an app that creates notifications at user defined times.
Basically I use two WinForms
:
NotificationObject
class that contains notification data such as message, title, due time.Form
number 2 is for tracking the notifications.When the program starts, Form
number 2 opens and there is a button where I can open Form
number 1. When form number 1 closes it saves the notification data to NotificationObject
class. Form
number 2 gets NotificationObject
that is created upon closing of Form
number 1 and adds it to ObservableCollection
. When something is added to ObservableCollection
, it creates a UserControl
with constructor parameters DueTime
, Title
and Message
. Then inside the UserControl
I use the System.Threading.Timer
and NotifyIcon
to create Notifications.
Even though I've set up the Callback
method to create NotifyIcon
Balloon, it doesn't show any.
Form number 1
public partial class NotificationCreator : Form
{
public NotificationObject ntfObj;
public NotificationCreator()
{
InitializeComponent();
}
private void createNotification_Click(object sender, EventArgs e)
{
if (String.IsNullOrEmpty(timeInput.Text))
{
MessageBox.Show(
"Please set the time.",
"Time is not set",
MessageBoxButtons.OK,
MessageBoxIcon.Error
);
return;
}
if (String.IsNullOrEmpty(titleInput.Text))
{
MessageBox.Show(
"Please set the title.",
"Title is not set",
MessageBoxButtons.OK,
MessageBoxIcon.Error
);
return;
}
if (String.IsNullOrEmpty(messageInput.Text))
{
MessageBox.Show(
"Please set the message.",
"Message is not set",
MessageBoxButtons.OK,
MessageBoxIcon.Error
);
return;
}
DateTime time = DateTime.Parse(timeInput.Text);
DateTime dt = new DateTime(dateInput.Value.Year,
dateInput.Value.Month,
dateInput.Value.Day,
time.Hour,
time.Minute,
0
);
ntfObj = new NotificationObject(dt, titleInput.Text, messageInput.Text);
Close();
Dispose();
}
private void timeInput_TextChanged(object sender, EventArgs e)
{
if (timeInput.Text.Length == 5)
{
try
{
DateTime dummy = DateTime.Parse(timeInput.Text);
if (dummy.Hour <= DateTime.Now.Hour && dummy.Minute <= DateTime.Now.Minute && dummy.Hour != 00 && dummy.Minute != 00)
{
MessageBox.Show("Please set the time for future",
"Invalid time",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
return;
}
return;
}
catch
{
MessageBox.Show("Please set a valid time",
"Invalid time",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
return;
}
}
}
private void dateInput_ValueChanged(object sender, EventArgs e)
{
if (dateInput.Value < DateTime.Now.AddDays(-1))
{
MessageBox.Show("Please set the date for future.",
"Invalid date",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
dateInput.Value = DateTime.Now;
return;
}
}
}
}
Form number 2
public partial class TrackingPanel : Form
{
ObservableCollection<NotificationObject> ntfList = new ObservableCollection<NotificationObject>();
public TrackingPanel()
{
InitializeComponent();
ntfList.CollectionChanged += NtfList_CollectionChanged;
}
private void NtfList_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
NotificationObject ntfObj = e.NewItems[0] as NotificationObject;
Notification ntf = new Notification(ntfObj.DueTime, ntfObj.ntfTitle, ntfObj.ntfMessage);
ntfPanel.Controls.Add(ntf);
}
}
private void TrackingPanel_Load(object sender, EventArgs e)
{}
private void TrackingPanel_Resize(object sender, EventArgs e)
{
if (WindowState == FormWindowState.Minimized)
{}
}
private void createNotification_Click(object sender, EventArgs e)
{
NotificationCreator Tool = new NotificationCreator();
Tool.ShowDialog();
ntfList.Add(Tool.ntfObj);
}
}
NotificationObject
/// <summary>
/// An object that represents the Notification and contains Notification information.
/// </summary>
public class NotificationObject
{
/// <summary>
/// Notification due time.
/// </summary>
public DateTime DueTime { get; set; }
/// <summary>
/// Title of Notification.
/// </summary>
public string ntfTitle { get; set; }
/// <summary>
/// Notification Message.
/// </summary>
public string ntfMessage{ get; set; }
public NotificationObject(DateTime dueTime, string title, string message)
{
DueTime = dueTime;
ntfTitle = title;
ntfMessage = message;
}
}
UserControl
public partial class Notification : UserControl
{
private readonly System.Threading.Timer timer;
public Notification(DateTime dt, string Title, string Message)
{
InitializeComponent();
this.Title.Text = Title;
this.Message.Text = Message;
ntfIco.Visible = false;
timer = new System.Threading.Timer(NotificationOccurs, null, dt - DateTime.Now, TimeSpan.FromSeconds(20));
}
private void NotificationOccurs(object state)
{
ntfIco.Visible = true;
ntfIco.ShowBalloonTip(3500, Title.Text, Message.Text, ToolTipIcon.Info);
ntfIco.Visible = false;
}
private void Notification_Load(object sender, EventArgs e)
{
ntfPic.Image = Properties.Resources.Search_Png;
}
}
EDIT
I used System.Windows.Forms.Timer in UserControl and still didn't worked.
public partial class Notification : UserControl
{
public Notification(DateTime dt, string Title, string Message)
{
InitializeComponent();
this.Title.Text = Title;
this.Message.Text = Message;
ntfIco.Visible = false;
Timer.Interval = (int)(dt - DateTime.Now).TotalMilliseconds;
Timer.Start();
}
private void Notification_Load(object sender, EventArgs e)
{
ntfPic.Image = Properties.Resources.Search_Png;
}
private void Timer_Tick(object sender, EventArgs e)
{
ntfIco.Visible = true;
ntfIco.ShowBalloonTip(3500, Title.Text, Message.Text, ToolTipIcon.Info);
Timer.Interval = 10 * 1000;
ntfIco.Visible = false;
}
}
From the comments discussion:
Be sure to set the Icon property of the notify icon.
Keep the WinForms Timer to be fine with the UI thread.
Don't set the notify icon visible to false just after the ballon tip popup else it closes.
Let the ballon tip fade itself.
If you want to hide the notify icon, do that on the BallonTipClosed event.
private void Timer_Tick(object sender, EventArgs e)
{
ntfIco.Visible = true;
ntfIco.ShowBalloonTip(3500, Title.Text, Message.Text, ToolTipIcon.Info);
Timer.Interval = 10 * 1000;
}
public Notification(DateTime dt, string Title, string Message)
{
InitializeComponent();
this.Title.Text = Title;
this.Message.Text = Message;
ntfIco.Visible = false;
ntfIco.BalloonTipClosed += (sender, e) => ntfIco.Visible = false;
Timer.Interval = (int)( dt - DateTime.Now ).TotalMilliseconds;
Timer.Start();
}