Toasts – Blame information for rev 26

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 // =====COPYRIGHT=====
2 // Code originally retrieved from http://www.vbforums.com/showthread.php?t=547778 - no license information supplied
3 // =====COPYRIGHT=====
4  
5 using System;
15 office 6 using System.Collections.Concurrent;
16 office 7 using System.Collections.Generic;
8 using System.Diagnostics;
1 office 9 using System.Drawing;
8 office 10 using System.IO;
15 office 11 using System.Linq;
8 office 12 using System.Media;
16 office 13 using System.Threading;
14 using System.Threading.Tasks;
1 office 15 using System.Windows.Forms;
11 office 16 using Toasts.Properties;
1 office 17  
18 namespace Toasts
19 {
2 office 20 public partial class ToastForm : Form
1 office 21 {
24 office 22 #region Public Fields and Properties
25 office 23  
24 office 24 public bool EnableChime { get; set; } = true;
25  
26 public int LingerTime { get; set; } = 5000;
27  
28 public FormAnimator.AnimationMethod AnimationMethod { get; set; } = FormAnimator.AnimationMethod.Slide;
29  
30 public FormAnimator.AnimationDirection AnimationDirection { get; set; } = FormAnimator.AnimationDirection.Up;
31  
32 public int AnimationDuration { get; set; } = 500;
33  
26 office 34 public byte[] Chime
35 {
36 get => _chime;
37 set
38 {
39 if (value is null)
40 {
41 return;
42 }
24 office 43  
26 office 44 _chime = value;
45 }
46 }
47  
24 office 48 /// <summary>
49 ///
50 /// </summary>
51 /// <remarks>clone the image for safety</remarks>
52 public Image Image
53 {
54 get => new Bitmap(imageBox.Image);
55 set => imageBox.Image = new Bitmap(value);
56 }
57  
58 #endregion
59  
1 office 60 #region Static Fields and Constants
61  
16 office 62 private static readonly object OpenNotificationsLock = new object();
1 office 63  
16 office 64 private static readonly HashSet<ToastForm> OpenNotifications = new HashSet<ToastForm>();
65  
1 office 66 #endregion
67  
12 office 68 #region Private Overrides
69  
70 protected override bool ShowWithoutActivation => true;
71  
72 protected override CreateParams CreateParams
73 {
74 get
75 {
76 var baseParams = base.CreateParams;
77  
78 const int WS_EX_NOACTIVATE = 0x08000000;
79 const int WS_EX_TOOLWINDOW = 0x00000080;
80 const int WS_EX_TOPMOST = 0x00000008;
81 baseParams.ExStyle |= WS_EX_NOACTIVATE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST;
82  
83 return baseParams;
84 }
85 }
86  
87 #endregion
88  
1 office 89 #region Constructors, Destructors and Finalizers
90  
11 office 91 private ToastForm()
7 office 92 {
93 InitializeComponent();
16 office 94 Region = Region.FromHrgn(NativeMethods.CreateRoundRectRgn(0, 0, Width - 5, Height - 5, 20, 20));
95  
96 _screenWidth = Screen.PrimaryScreen.WorkingArea.Width;
97 _screenHeight = Screen.PrimaryScreen.WorkingArea.Height;
15 office 98  
24 office 99 _formAnimator = new FormAnimator(this, AnimationMethod, AnimationDirection, AnimationDuration);
16 office 100  
101 using (var memoryStream = new MemoryStream())
15 office 102 {
16 office 103 Resources.normal.CopyTo(memoryStream);
104  
105 memoryStream.Position = 0L;
106  
24 office 107 Chime = memoryStream.ToArray();
15 office 108 }
109  
18 office 110 _showFormTaskCompletionSource = new TaskCompletionSource<object>();
111  
25 office 112 _toastTimer = new System.Timers.Timer { Enabled = false, AutoReset = false, Interval = LingerTime };
15 office 113 _toastTimer.Elapsed += ToastTimer_Elapsed;
7 office 114 }
11 office 115  
1 office 116 /// <summary>
15 office 117 /// Display a toast with a title, body and a logo indefinitely on screen.
1 office 118 /// </summary>
15 office 119 /// <param name="title">the toast title</param>
120 /// <param name="body">the toast body</param>
121 /// <param name="logo">the toast logo</param>
24 office 122 public ToastForm(string title, string body) : this()
15 office 123 {
124 labelTitle.Text = title;
125 labelBody.Text = body;
126 }
127  
128 /// <summary>
11 office 129 /// Clean up any resources being used.
7 office 130 /// </summary>
131 /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
132 protected override void Dispose(bool disposing)
133 {
16 office 134 if (disposing && components != null)
135 {
136 if (_toastTimer != null)
137 {
138 _toastTimer.Dispose();
139 _toastTimer = null;
140 }
141  
24 office 142 Image.Dispose();
16 office 143 components.Dispose();
144 }
7 office 145 base.Dispose(disposing);
146 }
147  
1 office 148 #endregion
149  
150 #region Private Delegates, Events, Enums, Properties, Indexers and Fields
151  
16 office 152 private readonly FormAnimator _formAnimator;
1 office 153  
16 office 154 private System.Timers.Timer _toastTimer;
1 office 155  
16 office 156 private readonly int _screenWidth;
157  
158 private readonly int _screenHeight;
21 office 159  
18 office 160 private readonly TaskCompletionSource<object> _showFormTaskCompletionSource;
16 office 161  
26 office 162 private byte[] _chime;
163  
1 office 164 #endregion
165  
166 #region Event Handlers
167  
25 office 168 private void ToastForm_Load(object sender, EventArgs e)
1 office 169 {
24 office 170 if (EnableChime)
16 office 171 {
24 office 172 Task.Factory.StartNew(() =>
9 office 173 {
24 office 174 using (var memoryStream = new MemoryStream(Chime))
16 office 175 {
24 office 176 using (var player = new SoundPlayer(memoryStream))
177 {
178 player.Play();
179 }
16 office 180 }
24 office 181 });
182 }
8 office 183  
16 office 184 try
8 office 185 {
16 office 186 lock (OpenNotificationsLock)
8 office 187 {
16 office 188 var notifications = OpenNotifications.ToArray();
8 office 189  
16 office 190 foreach (var openForm in notifications)
15 office 191 {
16 office 192 if (openForm == null)
193 {
194 continue;
195 }
7 office 196  
16 office 197 if (openForm.IsDisposed)
198 {
199 OpenNotifications.Remove(openForm);
15 office 200  
16 office 201 continue;
202 }
1 office 203  
16 office 204 if (openForm.IsHandleCreated != true)
205 {
206 continue;
207 }
4 office 208  
16 office 209 // Move each open form upwards to make room for this one
210 var handle = Handle;
211 openForm.BeginInvoke(new MethodInvoker(() =>
212 {
213 try
214 {
215 if (openForm.Handle == handle)
216 {
217 return;
218 }
1 office 219  
16 office 220 openForm.Top -= Height;
221 }
222 catch
223 {
224 Debug.WriteLine("Error while moving forms up.");
225 }
226 }));
227 }
15 office 228  
16 office 229 Invoke(new MethodInvoker(() =>
230 {
231 Location = new Point(_screenWidth - Width, _screenHeight - Height);
232 }));
233  
234 OpenNotifications.Add(this);
235  
25 office 236 _toastTimer.Enabled = true;
24 office 237 _toastTimer.Start();
16 office 238 }
239 }
240 catch
15 office 241 {
16 office 242 Debug.WriteLine("Error on form load event.");
15 office 243 }
1 office 244 }
245  
25 office 246 private void ToastForm_FormClosed(object sender, FormClosedEventArgs e)
1 office 247 {
16 office 248 try
1 office 249 {
16 office 250 lock (OpenNotificationsLock)
7 office 251 {
16 office 252 OpenNotifications.Remove(this);
7 office 253 }
16 office 254 }
255 catch
256 {
257 Debug.WriteLine("Error in form closed event.");
258 }
259 }
15 office 260  
25 office 261 private void ToastForm_Shown(object sender, EventArgs e)
16 office 262 {
263 // Reverse animation direction for hiding.
264 switch (_formAnimator.Direction)
265 {
266 case FormAnimator.AnimationDirection.Up:
267 _formAnimator.Direction = FormAnimator.AnimationDirection.Down;
268 break;
269 case FormAnimator.AnimationDirection.Down:
270 _formAnimator.Direction = FormAnimator.AnimationDirection.Up;
271 break;
272 case FormAnimator.AnimationDirection.Left:
273 _formAnimator.Direction = FormAnimator.AnimationDirection.Right;
274 break;
275 case FormAnimator.AnimationDirection.Right:
276 _formAnimator.Direction = FormAnimator.AnimationDirection.Left;
277 break;
1 office 278 }
18 office 279  
280 _showFormTaskCompletionSource.TrySetResult(new { });
1 office 281 }
282  
18 office 283 private async void ToastTimer_Elapsed(object sender, EventArgs e)
1 office 284 {
18 office 285 await _showFormTaskCompletionSource.Task;
286  
16 office 287 if (IsDisposed)
15 office 288 {
289 return;
290 }
1 office 291  
16 office 292 try
293 {
294 _toastTimer.Stop();
295 BeginInvoke(new MethodInvoker(() =>
296 {
297 lock (OpenNotificationsLock)
298 {
299 Close();
300 }
301 }));
302 }
303 catch
304 {
305 Debug.WriteLine("Error in timer elapsed event.");
306 }
1 office 307 }
308  
15 office 309 private void Toast_Click(object sender, EventArgs e)
1 office 310 {
16 office 311 try
312 {
21 office 313 BeginInvoke(new MethodInvoker(() =>
16 office 314 {
21 office 315 lock (OpenNotificationsLock)
316 {
317 Close();
318 }
319 }));
16 office 320 }
321 catch
322 {
323 Debug.WriteLine("Error in form click event.");
324 }
1 office 325 }
326  
327 #endregion
328 }
329 }