Toasts – Blame information for rev 25

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