Toasts – Blame information for rev 27

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