/// <summary>
        /// Raises the attached QueryContinueDrag event on a element.
        /// </summary>
        /// <param name="element">The element to raise the event on.</param>
        /// <param name="args">Information about the event.</param>
        internal static void OnQueryContinueDrag(this DependencyObject element, SW.QueryContinueDragEventArgs args)
        {
            if (!args.Handled)
            {
                IAcceptDrop acceptDrop = element as IAcceptDrop;
                if (acceptDrop != null)
                {
                    acceptDrop.OnQueryContinueDrag(args);
                }
            }
            ExtendedRoutedEventHandlerCollection <SW.QueryContinueDragEventHandler, SW.QueryContinueDragEventArgs> handlers = element.GetQueryContinueDragHandlers();

            if (handlers != null)
            {
                handlers.Raise(args);
            }
        }
        /// <summary>
        /// Raises the QueryContinueDragEvent on the drag source.
        /// </summary>
        /// <returns>Information about the QueryContinueDrag event.</returns>
        private SW.QueryContinueDragEventArgs OnDragSourceQueryContinueDrag()
        {
            SW.QueryContinueDragEventArgs queryContinueDragEventArgs =
                new SW.QueryContinueDragEventArgs()
            {
                Action         = SW.DragAction.Continue,
                EscapePressed  = _escapePressed,
                KeyStates      = KeyStates,
                OriginalSource = _dragSource
            };

            DependencyObject dragSource = _dragSource;

            if (dragSource != null)
            {
                queryContinueDragEventArgs =
                    dragSource.RaiseRoutedEvent(
                        queryContinueDragEventArgs,
                        (acc, e) => acc.OnQueryContinueDrag(e));
            }

            if (!queryContinueDragEventArgs.Handled)
            {
                if (queryContinueDragEventArgs.EscapePressed)
                {
                    queryContinueDragEventArgs.Action  = SW.DragAction.Cancel;
                    queryContinueDragEventArgs.Handled = true;
                }
                else if ((queryContinueDragEventArgs.KeyStates & SW.DragDropKeyStates.LeftMouseButton) != SW.DragDropKeyStates.LeftMouseButton)
                {
                    queryContinueDragEventArgs.Action  = (_lastGiveFeedbackEventArgs == null || _lastGiveFeedbackEventArgs.Effects != SW.DragDropEffects.None) ? SW.DragAction.Drop : SW.DragAction.Cancel;
                    queryContinueDragEventArgs.Handled = true;
                }
            }

            _dragSourceQueryContinueDrag.OnNext(
                Event.Create(
                    _dragSource,
                    queryContinueDragEventArgs));

            return(queryContinueDragEventArgs);
        }
        public IDisposable Subscribe(IObserver <SW.DragDropEffects> observer)
        {
            if (IsDragging)
            {
                throw new InvalidOperationException("A drag operation is already in progress.");
            }
            IsDragging = true;

            // Always execute a QueryContinueDrag first.
            _dragStarting.Take(1)
            .ObserveOnDispatcher()
            .Subscribe(
                dragEventArgs =>
            {
                SW.QueryContinueDragEventArgs args = OnDragSourceQueryContinueDrag();
                if (!(args.Handled && args.Action == SW.DragAction.Cancel))
                {
                    OnDragSourceGiveFeedback(_lastDragEventArgs);
                    _dragStarted.OnNext(dragEventArgs);
                }
            });

            IObservable <SW.DragDropKeyStates> keyStatesChanged =
                from dragStarted in _dragStarting
                where Application.Current != null
                from keyState in
                Application.Current.RootVisual
                .GetKeyStateChangedOnSelfAndSiblingsAlways(KeyStates)
                .TakeUntil(_dragCompleted)
                select keyState;

            keyStatesChanged.Subscribe(keyState => KeyStates = keyState);

            IObservable <bool> escapePressedChanged =
                from dragStated in _dragStarting
                where Application.Current != null
                from escapePressed in
                Application.Current.RootVisual
                .GetEscapePressedChangedOnSelfAndSiblingsAlways()
                .TakeUntil(_dragCompleted)
                select escapePressed;

            escapePressedChanged.Subscribe(pressed => _escapePressed = pressed);

            Observable
            .Merge(
                keyStatesChanged.IgnoreAll(),
                escapePressedChanged.IgnoreAll())
            .TakeUntil(_dragCompleted)
            .ObserveOnDispatcher()
            .Subscribe(_ => RaiseDragSourceEvents(_lastDragEventArgs));

            IObservable <IEvent <SW.DragEventArgs> > dragOver =
                from dragStartedEvent in _dragStarted
                let mouseMoveDragOver = GetMouseMoveDragOver()
                                        from dragMouseOverEvent in mouseMoveDragOver.TakeUntil(_dragCompleted)
                                        from pulseDragMouseOverEvent in
                                        Observable.Merge(
                    Observable.Return(dragMouseOverEvent),
                    Observable
                    .Interval(TimeSpan.FromMilliseconds(MouseOverPulseIntervalInMilliseconds))
                    .ObserveOnDispatcher()
                    .Select(_ =>
            {
                UIElement originalSource = dragMouseOverEvent.EventArgs.OriginalSource as UIElement;

                if (originalSource != null)
                {
                    Point pointWithinOriginalSource = dragMouseOverEvent.EventArgs.GetPosition((UIElement)dragMouseOverEvent.EventArgs.OriginalSource);
                    // if point is no longer within original source find the element
                    // in the tree that contains the point and make it the original source (and sender)
                    // or the next dragover event.
                    if (!new Rect(new Point(0, 0), originalSource.GetSize()).Contains(pointWithinOriginalSource))
                    {
                        originalSource = GetDragOverOriginalSource(dragMouseOverEvent.EventArgs);
                    }
                }

                return(Event.Create(originalSource, new SW.DragEventArgs(dragMouseOverEvent.EventArgs)
                {
                    OriginalSource = originalSource
                }));
            })
                    .TakeUntil(
                        Observable.Merge(
                            mouseMoveDragOver.IgnoreAll(),
                            _dragCompleted.IgnoreAll())))
                                        where IsDragging
                                        select pulseDragMouseOverEvent;

            dragOver
            .ObserveOnDispatcher()
            .Subscribe(dragOverEvent => OnDragOver(dragOverEvent.Sender, dragOverEvent.EventArgs));

            _dragStarting.OnNext(Event.Create(_dragSource, _dragStartEventArgs));
            _dragCompleted
            .ObserveOnDispatcher()
            .Subscribe(observer);

            return(new AnonymousDisposable(() => { Debug.Assert(false, "Should never detach from DragOperation."); }));
        }