Toasts – Blame information for rev 24

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