Toasts – Blame information for rev 33

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);
33 office 55 set => imageBox.Image = value;
24 office 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>
24 office 121 public ToastForm(string title, string body) : this()
15 office 122 {
123 labelTitle.Text = title;
27 office 124 htmlPanel1.Text = body;
15 office 125 }
126  
127 /// <summary>
11 office 128 /// Clean up any resources being used.
7 office 129 /// </summary>
130 /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
131 protected override void Dispose(bool disposing)
132 {
16 office 133 if (disposing && components != null)
33 office 134 {
135 components.Dispose();
136 }
137  
138 if (_toastTimer != null)
16 office 139 {
33 office 140 _toastTimer.Dispose();
141 _toastTimer = null;
142 }
16 office 143  
33 office 144 if (Image != null)
145 {
24 office 146 Image.Dispose();
33 office 147 Image = null;
16 office 148 }
33 office 149  
7 office 150 base.Dispose(disposing);
151 }
152  
1 office 153 #endregion
154  
155 #region Private Delegates, Events, Enums, Properties, Indexers and Fields
156  
16 office 157 private readonly FormAnimator _formAnimator;
1 office 158  
16 office 159 private System.Timers.Timer _toastTimer;
1 office 160  
16 office 161 private readonly int _screenWidth;
162  
163 private readonly int _screenHeight;
21 office 164  
18 office 165 private readonly TaskCompletionSource<object> _showFormTaskCompletionSource;
16 office 166  
26 office 167 private byte[] _chime;
168  
1 office 169 #endregion
170  
171 #region Event Handlers
172  
25 office 173 private void ToastForm_Load(object sender, EventArgs e)
1 office 174 {
24 office 175 if (EnableChime)
16 office 176 {
24 office 177 Task.Factory.StartNew(() =>
9 office 178 {
24 office 179 using (var memoryStream = new MemoryStream(Chime))
16 office 180 {
24 office 181 using (var player = new SoundPlayer(memoryStream))
182 {
183 player.Play();
184 }
16 office 185 }
24 office 186 });
187 }
8 office 188  
16 office 189 try
8 office 190 {
16 office 191 lock (OpenNotificationsLock)
8 office 192 {
16 office 193 var notifications = OpenNotifications.ToArray();
8 office 194  
16 office 195 foreach (var openForm in notifications)
15 office 196 {
16 office 197 if (openForm == null)
198 {
199 continue;
200 }
7 office 201  
16 office 202 if (openForm.IsDisposed)
203 {
204 OpenNotifications.Remove(openForm);
15 office 205  
16 office 206 continue;
207 }
1 office 208  
16 office 209 if (openForm.IsHandleCreated != true)
210 {
211 continue;
212 }
4 office 213  
16 office 214 // Move each open form upwards to make room for this one
215 var handle = Handle;
216 openForm.BeginInvoke(new MethodInvoker(() =>
217 {
218 try
219 {
220 if (openForm.Handle == handle)
221 {
222 return;
223 }
1 office 224  
16 office 225 openForm.Top -= Height;
226 }
227 catch
228 {
229 Debug.WriteLine("Error while moving forms up.");
230 }
231 }));
232 }
15 office 233  
16 office 234 Invoke(new MethodInvoker(() =>
235 {
236 Location = new Point(_screenWidth - Width, _screenHeight - Height);
237 }));
238  
239 OpenNotifications.Add(this);
240  
25 office 241 _toastTimer.Enabled = true;
24 office 242 _toastTimer.Start();
16 office 243 }
244 }
245 catch
15 office 246 {
16 office 247 Debug.WriteLine("Error on form load event.");
15 office 248 }
1 office 249 }
250  
25 office 251 private void ToastForm_FormClosed(object sender, FormClosedEventArgs e)
1 office 252 {
16 office 253 try
1 office 254 {
16 office 255 lock (OpenNotificationsLock)
7 office 256 {
16 office 257 OpenNotifications.Remove(this);
7 office 258 }
16 office 259 }
260 catch
261 {
262 Debug.WriteLine("Error in form closed event.");
263 }
264 }
15 office 265  
25 office 266 private void ToastForm_Shown(object sender, EventArgs e)
16 office 267 {
268 // Reverse animation direction for hiding.
269 switch (_formAnimator.Direction)
270 {
271 case FormAnimator.AnimationDirection.Up:
272 _formAnimator.Direction = FormAnimator.AnimationDirection.Down;
273 break;
274 case FormAnimator.AnimationDirection.Down:
275 _formAnimator.Direction = FormAnimator.AnimationDirection.Up;
276 break;
277 case FormAnimator.AnimationDirection.Left:
278 _formAnimator.Direction = FormAnimator.AnimationDirection.Right;
279 break;
280 case FormAnimator.AnimationDirection.Right:
281 _formAnimator.Direction = FormAnimator.AnimationDirection.Left;
282 break;
1 office 283 }
18 office 284  
285 _showFormTaskCompletionSource.TrySetResult(new { });
1 office 286 }
287  
18 office 288 private async void ToastTimer_Elapsed(object sender, EventArgs e)
1 office 289 {
18 office 290 await _showFormTaskCompletionSource.Task;
291  
16 office 292 if (IsDisposed)
15 office 293 {
294 return;
295 }
1 office 296  
16 office 297 try
298 {
299 _toastTimer.Stop();
300 BeginInvoke(new MethodInvoker(() =>
301 {
302 lock (OpenNotificationsLock)
303 {
304 Close();
305 }
306 }));
307 }
308 catch
309 {
310 Debug.WriteLine("Error in timer elapsed event.");
311 }
1 office 312 }
313  
15 office 314 private void Toast_Click(object sender, EventArgs e)
1 office 315 {
16 office 316 try
317 {
21 office 318 BeginInvoke(new MethodInvoker(() =>
16 office 319 {
21 office 320 lock (OpenNotificationsLock)
321 {
322 Close();
323 }
324 }));
16 office 325 }
326 catch
327 {
328 Debug.WriteLine("Error in form click event.");
329 }
1 office 330 }
331  
332 #endregion
333 }
334 }