public void Enqueue(object content, object actionContent, Action <object> actionHandler,
                            object actionArgument, bool promote, bool neverConsiderToBeDuplicate)
        {
            if (content == null)
            {
                throw new ArgumentNullException(nameof(content));
            }

            if (actionContent == null ^ actionHandler == null)
            {
                throw new ArgumentException("All action arguments must be provided if any are provided.",
                                            actionContent != null ? nameof(actionContent) : nameof(actionHandler));
            }

            var snackbarMessageQueueItem = new SnackbarMessageQueueItem(content, actionContent, actionHandler,
                                                                        actionArgument, promote, neverConsiderToBeDuplicate);

            if (promote)
            {
                InsertAsLastNotPromotedNode(snackbarMessageQueueItem);
            }
            else
            {
                _snackbarMessages.AddLast(snackbarMessageQueueItem);
            }

            _messageWaitingEvent.Set();
        }
 private static SnackbarMessage Create(SnackbarMessageQueueItem messageQueueItem)
 {
     return(new SnackbarMessage
     {
         Content = messageQueueItem.Content,
         ActionContent = messageQueueItem.ActionContent
     });
 }
        private static void DoActionCallback(SnackbarMessageQueueItem messageQueueItem)
        {
            try
            {
                messageQueueItem.ActionHandler(messageQueueItem.ActionArgument);
            }
            catch (Exception exc)
            {
                Trace.WriteLine("Error during SnackbarMessageQueue message action callback, exception will be rethrown.");
                Trace.WriteLine($"{exc.Message} ({exc.GetType().FullName})");
                Trace.WriteLine(exc.StackTrace);

                throw;
            }
        }
        private void InsertAsLastNotPromotedNode(SnackbarMessageQueueItem snackbarMessageQueueItem)
        {
            var node = _snackbarMessages.First;

            while (node != null)
            {
                if (!node.Value.IsPromoted)
                {
                    _snackbarMessages.AddBefore(node, snackbarMessageQueueItem);
                    return;
                }
                node = node.Next;
            }
            _snackbarMessages.AddLast(snackbarMessageQueueItem);
        }
        private async Task ShowAsync(Snackbar snackbar, SnackbarMessageQueueItem messageQueueItem)
        {
            await Task.Run(async() =>
            {
                //create and show the message, setting up all the handles we need to wait on
                var actionClickWaitHandle         = new ManualResetEvent(false);
                var mouseNotOverManagedWaitHandle =
                    await
                    snackbar.Dispatcher.InvokeAsync(
                        () => CreateAndShowMessage(snackbar, messageQueueItem, actionClickWaitHandle));
                var durationPassedWaitHandle = new ManualResetEvent(false);
                DurationMonitor.Start(_messageDuration.Add(snackbar.ActivateStoryboardDuration),
                                      _pausedEvent, durationPassedWaitHandle, _disposedEvent);

                //wait until time span completed (including pauses and mouse overs), or the action is clicked
                await WaitForCompletionAsync(mouseNotOverManagedWaitHandle, durationPassedWaitHandle, actionClickWaitHandle);

                //close message on snackbar
                await
                snackbar.Dispatcher.InvokeAsync(
                    () => snackbar.SetCurrentValue(Snackbar.IsActiveProperty, false));

                //we could wait for the animation event, but just doing
                //this for now...at least it is prevent extra call back hell
                _disposedEvent.WaitOne(snackbar.DeactivateStoryboardDuration);

                //remove message on snackbar
                await snackbar.Dispatcher.InvokeAsync(
                    () => snackbar.SetCurrentValue(Snackbar.MessageProperty, null));

                mouseNotOverManagedWaitHandle.Dispose();
                durationPassedWaitHandle.Dispose();
            })
            .ContinueWith(t =>
            {
                if (t.Exception == null)
                {
                    return;
                }

                var exc = t.Exception.InnerExceptions.FirstOrDefault() ?? t.Exception;
                Trace.WriteLine("Error occured whilst showing Snackbar, exception will be rethrown.");
                Trace.WriteLine($"{exc.Message} ({exc.GetType().FullName})");
                Trace.WriteLine(exc.StackTrace);

                throw t.Exception;
            });
        }
        private static MouseNotOverManagedWaitHandle CreateAndShowMessage(UIElement snackbar,
                                                                          SnackbarMessageQueueItem messageQueueItem, EventWaitHandle actionClickWaitHandle)
        {
            var clickCount      = 0;
            var snackbarMessage = Create(messageQueueItem);

            snackbarMessage.ActionClick += (sender, args) =>
            {
                if (++clickCount == 1)
                {
                    DoActionCallback(messageQueueItem);
                }
                actionClickWaitHandle.Set();
            };
            snackbar.SetCurrentValue(Snackbar.MessageProperty, snackbarMessage);
            snackbar.SetCurrentValue(Snackbar.IsActiveProperty, true);
            return(new MouseNotOverManagedWaitHandle(snackbar));
        }