Beispiel #1
0
        /// <summary>
        /// Gets an enumerable of all dragged items.
        /// </summary>
        /// <param name="dataObject">The <see cref="IDataObject"/> which defines the dragged items.</param>
        /// <param name="control">The control from which items will be derived.</param>
        /// <returns>Returns an enumerable of all dragged items which will be empty if no items were found.</returns>
        internal static IEnumerable <ToolboxTreeNodeModel> GetDraggedModels(IDataObject dataObject, TreeListBox control)
        {
            string format = TreeListBox.ItemDataFormat;

            if (dataObject.GetDataPresent(format))
            {
                string data = dataObject.GetData(format) as string;
                if (!string.IsNullOrWhiteSpace(data))
                {
                    foreach (var fullPath in SplitItemFullPaths(data))
                    {
                        if (control.GetItemByFullPath(fullPath) is ToolboxTreeNodeModel itemModel)
                        {
                            yield return(itemModel);
                        }
                    }
                }
            }
        }
Beispiel #2
0
        /// <summary>
        /// Notifies that a drag event occurred over a target item, requests that appropriate updates are made to the supplied <c>DragEventArgs</c>,
        /// and requests that the allowed drop area is returned for visual target feedback.
        /// </summary>
        /// <param name="e">The <see cref="DragEventArgs"/> whose effects should be updated.</param>
        /// <param name="targetControl">The target control, over which the event occurred</param>
        /// <param name="targetItem">The target item, which could be <see langword="null"/> if dragging below the last tree item.</param>
        /// <param name="dropArea">A <see cref="TreeItemDropArea"/> indicating the drop area over the target item.</param>
        /// <returns>
        /// A <see cref="TreeItemDropArea"/> indicating the allowed drop area, which will be used for visual feedback to the end user.
        /// Return <c>TreeItemDropArea.None</c> for no visual feedback.
        /// </returns>
        /// <remarks>
        /// The default implementation of this method sets the <c>e.Effects</c> to <c>DragDropEffects.None</c> and returns that no drop area is allowed.
        /// Override this method if you wish to support dropping and add logic to properly handle the dragged data.
        /// </remarks>
        public override TreeItemDropArea OnDragOver(DragEventArgs e, TreeListBox targetControl, object targetItem, TreeItemDropArea dropArea)
        {
            // If the drag is over an item and there is item data present...
            if ((targetItem != null) && (dropArea != TreeItemDropArea.None) && (e.Data.GetDataPresent(TreeListBox.ItemDataFormat)))
            {
                var fullPaths = e.Data.GetData(TreeListBox.ItemDataFormat) as string;
                if (!string.IsNullOrEmpty(fullPaths))
                {
                    // Locate the first item based on full path
                    object firstItem = null;
                    foreach (var fullPath in fullPaths.Split(new char[] { '\r', '\n' }))
                    {
                        if (!string.IsNullOrEmpty(fullPath))
                        {
                            var item = targetControl.GetItemByFullPath(fullPath);
                            if (item != null)
                            {
                                firstItem = item;
                                break;
                            }
                        }
                    }

                    if (firstItem != null)
                    {
                        // Ensure that the first item is already in the target control (nav will be null if not)... if allowing drag/drop onto external
                        //   controls, you cannot use the item navigator and must rely on your own item hierarchy logic
                        var firstItemNav = targetControl.GetItemNavigator(firstItem);
                        if (firstItemNav != null)
                        {
                            // Only support a single effect (you could add support for other effects like Copy if the Ctrl key is down here)
                            if ((e.AllowedEffects & DragDropEffects.Move) == DragDropEffects.Move)
                            {
                                e.Effects = DragDropEffects.Move;
                                e.Handled = true;
                            }

                            switch (e.Effects)
                            {
                            case DragDropEffects.Move:
                                // Coerce the resulting drop-area so that if dragging 'after' an item that has a next sibling, the drop area
                                //   becomes 'on' the item instead... can still get between the items by dragging 'before' the next sibling in this scenario
                                if (dropArea == TreeItemDropArea.After)
                                {
                                    var targetItemNav = targetControl.GetItemNavigator(targetItem);
                                    if ((targetItemNav != null) && (targetItemNav.GoToNextSibling()))
                                    {
                                        dropArea = TreeItemDropArea.On;
                                    }
                                }

                                return(dropArea);
                            }
                        }
                    }
                }
            }

            e.Effects = DragDropEffects.None;
            return(TreeItemDropArea.None);
        }
Beispiel #3
0
        /// <summary>
        /// Notifies that a drop event occurred over a target item and requests that appropriate updates are made to the supplied <c>DragEventArgs</c>.
        /// </summary>
        /// <param name="e">The <see cref="DragEventArgs"/> whose effects should be updated.</param>
        /// <param name="targetControl">The target control, over which the event occurred</param>
        /// <param name="targetItem">The target item, which could be <see langword="null"/> if dragging below the last tree item.</param>
        /// <param name="dropArea">A <see cref="TreeItemDropArea"/> indicating the drop area over the target item.</param>
        /// <remarks>
        /// The default implementation of this method sets the <c>e.Effects</c> to <c>DragDropEffects.None</c> and takes no further action.
        /// Override this method if you wish to support dropping and add logic to properly handle the dragged data.
        /// </remarks>
        public override void OnDrop(DragEventArgs e, TreeListBox targetControl, object targetItem, TreeItemDropArea dropArea)
        {
            var originalEffects = e.Effects;

            e.Effects = DragDropEffects.None;

            // If the drag is over an item and there is item data present...
            var targetModel = targetItem as TreeNodeModel;

            if ((targetModel != null) && (dropArea != TreeItemDropArea.None) && (e.Data.GetDataPresent(TreeListBox.ItemDataFormat)))
            {
                // Resolve the real target item (in case the drop area is above or below the target item)
                var targetDropIndex = targetModel.Children.Count;
                switch (dropArea)
                {
                case TreeItemDropArea.Before:
                case TreeItemDropArea.After:
                    var nav = targetControl.GetItemNavigator(targetItem);
                    if (nav != null)
                    {
                        var targetChildModel = targetModel;
                        var targetChildItem  = targetItem;

                        if (!nav.GoToParent())
                        {
                            return;
                        }
                        targetItem  = nav.CurrentItem;
                        targetModel = targetItem as TreeNodeModel;
                        if (targetModel == null)
                        {
                            return;
                        }

                        var index = targetModel.Children.IndexOf(targetChildModel);
                        if (index != -1)
                        {
                            targetDropIndex = index + (dropArea == TreeItemDropArea.After ? 1 : 0);
                        }
                    }
                    break;
                }

                // Get the items
                var fullPaths = e.Data.GetData(TreeListBox.ItemDataFormat) as string;
                if (!string.IsNullOrEmpty(fullPaths))
                {
                    // Locate items based on full path
                    var items = new List <object>();
                    foreach (var fullPath in fullPaths.Split(new char[] { '\r', '\n' }))
                    {
                        if (!string.IsNullOrEmpty(fullPath))
                        {
                            var item = targetControl.GetItemByFullPath(fullPath);
                            if (item != null)
                            {
                                items.Add(item);
                            }
                        }
                    }

                    if (items.Count > 0)
                    {
                        // Check each item and validate that various drop operations are allowed before actually executing the drop
                        foreach (var item in items)
                        {
                            if (item == targetItem)
                            {
                                MessageBox.Show("Cannot drop an item on itself.", "Drag and Drop", MessageBoxButton.OK);
                                return;
                            }
                            else
                            {
                                var nav = targetControl.GetItemNavigator(item);
                                if (nav == null)
                                {
                                    MessageBox.Show("Cannot drop from a different control.", "Drag and Drop", MessageBoxButton.OK);
                                    return;
                                }
                                else
                                {
                                    if (nav.GoToCommonAncestor(targetItem))
                                    {
                                        if (nav.CurrentItem == item)
                                        {
                                            MessageBox.Show("Cannot drop onto a descendant item.", "Drag and Drop", MessageBoxButton.OK);
                                            return;
                                        }
                                    }
                                }
                            }
                        }

                        // Only support a single effect (you could add support for other effects like Copy if the Ctrl key is down here)
                        if ((originalEffects & DragDropEffects.Move) == DragDropEffects.Move)
                        {
                            e.Effects = DragDropEffects.Move;
                            e.Handled = true;
                        }

                        // Move items
                        foreach (var item in items)
                        {
                            var nav = targetControl.GetItemNavigator(item);
                            if (nav.GoToParent())
                            {
                                var itemModel   = item as TreeNodeModel;
                                var parentModel = nav.CurrentItem as TreeNodeModel;
                                if ((itemModel != null) && (parentModel != null))
                                {
                                    var index = parentModel.Children.IndexOf(itemModel);
                                    if (index != -1)
                                    {
                                        if ((parentModel == targetModel) && (index < targetDropIndex))
                                        {
                                            targetDropIndex--;
                                        }

                                        parentModel.Children.RemoveAt(index);
                                    }
                                    else
                                    {
                                        break;
                                    }
                                }
                                else
                                {
                                    break;
                                }

                                targetModel.Children.Insert(Math.Max(0, Math.Min(targetModel.Children.Count, targetDropIndex++)), itemModel);
                                targetModel.IsExpanded = true;

                                // Focus the last item
                                if (items[items.Count - 1] == item)
                                {
                                    targetControl.FocusItem(itemModel);
                                }
                            }
                        }
                    }
                }
            }
        }