示例#1
0
        private async Task ShowAsync(Snackbar snackbar, SnackbarMessageQueueItem messageQueueItem, ManualResetEvent actionClickWaitHandle)
        {
            snackbar.Visibility = Visibility.Visible;
            snackbar.SetCurrentValue(Snackbar.IsActiveProperty, false);
            //create and show the message, setting up all the handles we need to wait on
            var mouseNotOverManagedWaitHandle = CreateAndShowMessage(snackbar, messageQueueItem, actionClickWaitHandle);
            var durationPassedWaitHandle      = new ManualResetEvent(false);

            StartDuration(messageQueueItem.Duration.Add(snackbar.ActivateStoryboardDuration), durationPassedWaitHandle);

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

            //close message on snackbar
            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
            await Task.Delay(snackbar.DeactivateStoryboardDuration);

            //remove message on snackbar
            snackbar.SetCurrentValue(Snackbar.MessageProperty, null);

            mouseNotOverManagedWaitHandle.Dispose();
            durationPassedWaitHandle.Dispose();
        }
示例#2
0
        private static MouseNotOverManagedWaitHandle CreateAndShowMessage(UIElement snackbar,
                                                                          SnackbarMessageQueueItem messageQueueItem, EventWaitHandle actionClickWaitHandle)
        {
            var clickCount      = 0;
            var snackbarMessage = new SnackbarMessage
            {
                Content       = messageQueueItem.Content,
                ActionContent = messageQueueItem.ActionContent
            };

            snackbarMessage.MouseDown += (sender, args) =>
            {
                //snackbar.Visibility = Visibility.Collapsed;
                actionClickWaitHandle.Set();
            };
            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));
        }
示例#3
0
        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 void InsertItem(SnackbarMessageQueueItem item)
        {
            lock (_snackbarMessagesLock)
            {
                var added = false;
                var node  = _snackbarMessages.First;
                while (node != null)
                {
                    if (!IgnoreDuplicate && item.IsDuplicate(node.Value))
                    {
                        return;
                    }

                    if (item.IsPromoted && !node.Value.IsPromoted)
                    {
                        _snackbarMessages.AddBefore(node, item);
                        added = true;
                        break;
                    }
                    node = node.Next;
                }
                if (!added)
                {
                    _snackbarMessages.AddLast(item);
                }
            }

            _dispatcher.InvokeAsync(ShowNextAsync);
        }
示例#5
0
        private static void DoActionCallback(SnackbarMessageQueueItem messageQueueItem)
        {
            try
            {
                var action = messageQueueItem.ActionHandler as Action;
                if (action != null)
                {
                    action();
                    return;
                }

                if (messageQueueItem.ArgumentType == null)
                {
                    return;
                }

                var genericType = typeof(Action <>).MakeGenericType(messageQueueItem.ArgumentType);
                var method      = genericType.GetMethod("Invoke");
                method.Invoke(messageQueueItem.ActionHandler, new[] { 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;
            }
        }
示例#6
0
        private async Task ShowAsync(Snackbar snackbar, SnackbarMessageQueueItem messageQueueItem, ManualResetEvent actionClickWaitHandle)
        {
            //create and show the message, setting up all the handles we need to wait on
            var tuple           = CreateAndShowMessage(snackbar, messageQueueItem, actionClickWaitHandle);
            var snackbarMessage = tuple.Item1;
            var mouseNotOverManagedWaitHandle = tuple.Item2;

            var durationPassedWaitHandle = new ManualResetEvent(false);

            StartDuration(messageQueueItem.Duration.Add(snackbar.ActivateStoryboardDuration), durationPassedWaitHandle);

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

            //close message on snackbar
            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
            await Task.Delay(snackbar.DeactivateStoryboardDuration);

            //this prevents missing resource warnings after the message is removed from the Snackbar
            //see https://github.com/MaterialDesignInXAML/MaterialDesignInXamlToolkit/issues/2040
            snackbarMessage.Resources = SnackbarMessage.defaultResources;

            //remove message on snackbar
            snackbar.SetCurrentValue(Snackbar.MessageProperty, null);

            mouseNotOverManagedWaitHandle.Dispose();
            durationPassedWaitHandle.Dispose();
        }
示例#7
0
        public void Enqueue <TArgument>(object content, object actionContent, Action <TArgument> actionHandler,
                                        TArgument actionArgument, bool promote)
        {
            if (content == null)
            {
                throw new ArgumentNullException(nameof(content));
            }

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

            var argumentType = actionArgument != null ? typeof(TArgument) : null;

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

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

            _messageWaitingEvent.Set();
        }
示例#8
0
 private static SnackbarMessage Create(SnackbarMessageQueueItem messageQueueItem)
 {
     return(new SnackbarMessage
     {
         Content = messageQueueItem.Content,
         ActionContent = messageQueueItem.ActionContent
     });
 }
示例#9
0
        private async void PumpAsync()
        {
            while (!_isDisposed)
            {
                var eventId = WaitHandle.WaitAny(new WaitHandle[] { _disposedEvent, _messageWaitingEvent });
                if (eventId == 0)
                {
                    continue;
                }

                Snackbar exemplar = _pairedSnackbars.FirstOrDefault();
                if (exemplar == null)
                {
                    Trace.TraceWarning(
                        "A snackbar message as waiting, but no Snackbar instances are assigned to the message queue.");
                    _disposedEvent.WaitOne(TimeSpan.FromSeconds(1));
                    continue;
                }

                //find a target
                var snackbar = await FindSnackbar(exemplar.Dispatcher);

                //show message
                if (snackbar != null)
                {
                    SnackbarMessageQueueItem message = _snackbarMessages.First.Value;
                    _snackbarMessages.RemoveFirst();
                    if (_latestShownItem == null ||
                        IgnoreDuplicate ||
                        message.IgnoreDuplicate ||
                        !Equals(_latestShownItem.Item1.Content, message.Content) ||
                        !Equals(_latestShownItem.Item1.ActionContent, message.ActionContent) ||
                        _latestShownItem.Item2 <= DateTime.Now.Subtract(_messageDuration))
                    {
                        await ShowAsync(snackbar, message);

                        _latestShownItem = new Tuple <SnackbarMessageQueueItem, DateTime>(message, DateTime.Now);
                    }
                }
                else
                {
                    //no snackbar could be found, take a break
                    _disposedEvent.WaitOne(TimeSpan.FromSeconds(1));
                }

                if (_snackbarMessages.Count > 0)
                {
                    _messageWaitingEvent.Set();
                }
                else
                {
                    _messageWaitingEvent.Reset();
                }
            }
        }
示例#10
0
        /// <summary>
        /// Checks if given item is a duplicate to this
        /// </summary>
        /// <param name="item">Item to check for duplicate</param>
        /// <returns><c>true</c> if given item is a duplicate to this, <c>false</c> otherwise</returns>
        public bool IsDuplicate(SnackbarMessageQueueItem item)
        {
            if (item is null)
            {
                throw new ArgumentNullException(nameof(item));
            }

            return(!IgnoreDuplicate &&
                   Equals(item.Content, Content) &&
                   Equals(item.ActionContent, ActionContent));
        }
示例#11
0
        public bool IsDuplicate(SnackbarMessageQueueItem value)
        {
            if (value is null)
            {
                throw new ArgumentNullException(nameof(value));
            }

            if (AlwaysShow)
            {
                return(false);
            }
            return(Equals(value));
        }
        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;
            }
        }
示例#13
0
        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);
        }
示例#14
0
        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(messageQueueItem.Duration.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;
            });
        }
示例#15
0
        private static MouseNotOverManagedWaitHandle CreateAndShowMessage(UIElement snackbar,
                                                                          SnackbarMessageQueueItem messageQueueItem, EventWaitHandle actionClickWaitHandle)
        {
            var             clickCount      = 0;
            SnackbarMessage 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));
        }
        public void Enqueue(object content, object actionContent, Action <object> actionHandler,
                            object actionArgument, bool promote, bool neverConsiderToBeDuplicate, TimeSpan?durationOverride = null)
        {
            if (content is null)
            {
                throw new ArgumentNullException(nameof(content));
            }

            if (actionContent is null ^ actionHandler is 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, durationOverride ?? _messageDuration,
                                                                        actionContent, actionHandler, actionArgument, promote, neverConsiderToBeDuplicate);

            InsertItem(snackbarMessageQueueItem);
        }
示例#17
0
        private void InsertItem(SnackbarMessageQueueItem item)
        {
            var node = _snackbarMessages.First;

            while (node != null)
            {
                if (!IgnoreDuplicate && item.IsDuplicate(node.Value))
                {
                    return;
                }

                if (item.IsPromoted && !node.Value.IsPromoted)
                {
                    _snackbarMessages.AddBefore(node, item);
                    return;
                }
                node = node.Next;
            }
            _snackbarMessages.AddLast(item);
        }