Toasts – Rev 53
?pathlinks?
using System;
using System.Collections.Concurrent;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Threading.Tasks.Dataflow;
using System.Windows.Forms;
using Markdig;
using Markdig.Renderers;
namespace Toasts
{
public class ToastDisplay : IDisposable
{
private readonly CancellationToken _cancellationToken;
private readonly BufferBlock<ToastDisplayData> _toastFormBufferBlock;
private ConcurrentBag<IDisposable> tplDataflowLinks;
private readonly TransformBlock<ToastDisplayData, ToastDisplayData> _toastBodyTransformBlock;
private readonly ActionBlock<ToastDisplayData> _toastFormActionBlock;
private ToastDisplay()
{
tplDataflowLinks = new ConcurrentBag<IDisposable>();
}
public ToastDisplay(CancellationToken cancellationToken) : this()
{
_cancellationToken = cancellationToken;
_toastFormBufferBlock = new BufferBlock<ToastDisplayData>(new DataflowBlockOptions { CancellationToken = _cancellationToken });
_toastBodyTransformBlock = new TransformBlock<ToastDisplayData, ToastDisplayData>(ToastBodyToHTML,
new ExecutionDataflowBlockOptions { CancellationToken = _cancellationToken });
_toastFormActionBlock = new ActionBlock<ToastDisplayData>(DisplayForm, new ExecutionDataflowBlockOptions { CancellationToken = _cancellationToken });
tplDataflowLinks.Add(_toastFormBufferBlock.LinkTo(_toastBodyTransformBlock, new DataflowLinkOptions { PropagateCompletion = true }));
tplDataflowLinks.Add(_toastBodyTransformBlock.LinkTo(DataflowBlock.NullTarget<ToastDisplayData>(), new DataflowLinkOptions { PropagateCompletion = true }, result => result == null));
tplDataflowLinks.Add(_toastBodyTransformBlock.LinkTo(_toastFormActionBlock, new DataflowLinkOptions { PropagateCompletion = true }));
}
private ToastDisplayData ToastBodyToHTML(ToastDisplayData toastDisplayData)
{
switch (toastDisplayData.Content)
{
case "text/markdown":
var pipeline = new MarkdownPipelineBuilder().UsePipeTables().Build();
var html = Markdown.ToHtml(toastDisplayData.Body, pipeline);
toastDisplayData.Body = html;
break;
}
return toastDisplayData;
}
public void Dispose()
{
while (tplDataflowLinks.TryTake(out var disposable))
{
disposable.Dispose();
}
}
private static void DisplayForm(ToastDisplayData toastPayload)
{
var thread = new Thread(() =>
{
try
{
var toastForm = new ToastForm(toastPayload.Title, toastPayload.Body)
{
EnableChime = toastPayload.EnableChime,
Chime = toastPayload.Chime ?? toastPayload.Chime,
LingerTime = toastPayload.LingerTime,
Image = toastPayload.Image,
ContentType = toastPayload.Content,
EnablePin = toastPayload.EnablePin,
PinPoint = toastPayload.PinPoint,
UserAgent = toastPayload.UserAgent
};
var formClosingEvent = new ManualResetEvent(false);
void OnFormClosing(object sender, EventArgs args)
{
toastForm.FormClosing -= OnFormClosing;
formClosingEvent.Set();
}
toastForm.FormClosing += OnFormClosing;
Application.Run(toastForm);
var timeout = toastPayload.EnablePin ? -1 : toastPayload.LingerTime;
formClosingEvent.WaitOne(timeout);
toastForm.FormClosing -= OnFormClosing;
toastForm.Close();
if (!toastForm.IsDisposed)
{
toastForm.Dispose();
}
toastForm = null;
formClosingEvent.Dispose();
formClosingEvent = null;
}
catch (Win32Exception)
{
// ignore window creation errors for now
}
catch (COMException)
{
// ignore window creation errors for now
}
catch(InvalidOperationException)
{
// animation clutter
}
catch (ArgumentException)
{
// animation clutter
}
catch(Exception exception)
{
Debug.WriteLine(exception);
}
})
{
IsBackground = true
};
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
public async Task Queue(ToastDisplayData toastPayload)
{
await _toastFormBufferBlock.SendAsync(toastPayload, _cancellationToken);
}
}
}
Generated by GNU Enscript 1.6.5.90.