/// <summary>
        /// Occurs when activity of the current drag drop operation has changed.
        /// </summary>
        /// <param name="sender">The event source.</param>
        /// <param name="e">The event data.</param>
        protected virtual void OnDragActivityChanged(object?sender, EventArgs e)
        {
            Contract.RequireNotNull(sender, out IDragSourceControl Ctrl);

            bool IsHandled = false;

            switch (Ctrl.DragActivity)
            {
            case DragActivity.Idle:
                IsHandled = true;
                break;

            case DragActivity.Starting:
                bool IsDragPossible = DragSource.IsDragPossible(out _, out IList ItemList);
                Debug.Assert(IsDragPossible);

                SetDragItemList(DragSource, ItemList);

                CancellationToken cancellation = new CancellationToken();
                NotifyDragStarting(cancellation);
                if (cancellation.IsCanceled)
                {
                    Ctrl.CancelDrag();
                }

                IsHandled = true;
                break;

            case DragActivity.Started:
                DataObject      Data           = new DataObject(DragSource.GetType(), DragSource);
                DragDropEffects AllowedEffects = DragDropEffects.Move;
                if (DragSource.AllowDropCopy)
                {
                    AllowedEffects |= DragDropEffects.Copy;
                }
                DragDrop.DoDragDrop(this, Data, AllowedEffects);
                ClearCurrentDropTarget();

                IsHandled = true;
                break;

            default:
                break;
            }

            Debug.Assert(IsHandled);
        }
        /// <summary>
        /// Gets the drag source from arguments of a drag drop event.
        /// </summary>
        /// <param name="e">The event data.</param>
        /// <param name="dragSource">The drag source upon return.</param>
        /// <returns>True if successful.</returns>
        protected virtual bool GetValidDragSourceFromArgs(DragEventArgs e, out IDragSourceControl dragSource)
        {
            if (e.Data.GetDataPresent(DragSource.GetType()))
            {
                if (e.Data.GetData(DragSource.GetType()) is IDragSourceControl AsDragSource)
                {
                    if (AsDragSource.HasDragItemList(out object RootItem, out IList _) && IsSameTypeAsContent(RootItem))
                    {
                        dragSource = AsDragSource;
                        return(true);
                    }
                }
            }

            Contract.Unused(out dragSource);
            return(false);
        }
        /// <summary>
        /// Invoked when an unhandled <see cref="UIElement.Drop"/> attached event reaches an element in its route that is derived from this class.
        /// </summary>
        /// <param name="e">The event data.</param>
        protected override void OnDrop(DragEventArgs e)
        {
            e.Effects = GetAllowedDropEffects(e);
            e.Handled = true;

            if (e.Effects != DragDropEffects.None)
            {
                ExtendedTreeViewItemBase?ItemContainer = GetEventSourceItem(e);
                IDragSourceControl       AsDragSource  = (IDragSourceControl)e.Data.GetData(DragSource.GetType());
                bool   IsDragPossible  = AsDragSource.IsDragPossible(out object SourceItem, out IList ItemList);
                object?DestinationItem = ItemContainer != null ? ItemContainer.Content : null;

                UnselectAll();

                if (IsDragPossible && DestinationItem != null)
                {
                    IList CloneList = CreateItemList();

                    Debug.Assert(CloneList.Count == 0);
                    NotifyPreviewDropCompleted(DestinationItem, e.Effects, ItemList, CloneList);

                    if (e.Effects == DragDropEffects.Copy)
                    {
                        DragDropCopy(SourceItem, DestinationItem, ItemList, CloneList);
                    }
                    else if (e.Effects == DragDropEffects.Move)
                    {
                        DragDropMove(SourceItem, DestinationItem, ItemList);
                    }

                    Debug.Assert(CloneList.Count > 0 || e.Effects != DragDropEffects.Copy);
                    NotifyDropCompleted(DestinationItem, e.Effects, ItemList, CloneList);

                    Expand(DestinationItem);
                }
            }
        }