简体   繁体   中英

Preventing Flex tree drop feedback

I'd like to allow a user to reorder items within a Flex tree folder, but not move those items outside of the folder. I can prevent the outside drop from succeeding, but I'd like to give the user feedback (before the drop) that the drop will not succeed. I've found many examples regarding the drop action, but nothing that shows the correct feedback to the user.

According to the Tree documentation, I should be able to call DragManager.showFeedback(DragManager.NONE) during the dragOver event, but that's not working. A short sample project is included below. Is there any way to indicate to the user during a drag event that the drop will not succeed?

Thanks in advance for any solution!

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
                       xmlns:s="library://ns.adobe.com/flex/spark"
                       xmlns:mx="library://ns.adobe.com/flex/mx"
                       width="354"
                       height="480">
    <fx:Script>
        <![CDATA[
            import mx.collections.ArrayCollection;
            import mx.core.IUIComponent;
            import mx.core.mx_internal;
            import mx.events.DragEvent;
            import mx.events.FlexEvent;
            import mx.managers.DragManager;

            protected function tree_dragEnterHandler(event:DragEvent):void {
                // only items can be dragged - not folders
                if (tree.selectedItem.@type == "item") {
                    DragManager.acceptDragDrop(IUIComponent(event.currentTarget));
                } else {
                    event.preventDefault();
                    DragManager.showFeedback(DragManager.NONE);
                }
            }

            protected function tree_dragOverHandler(event:DragEvent):void {
                var dropData:Object = tree.mx_internal::_dropData;
                var dragItem:XML = event.dragSource.dataForFormat("treeItems")[0];
                if (!dropData || !dropData.parent || !dragItem.parent() || dragItem.parent() != dropData.parent) {
                    trace("preventing drop");
                    DragManager.showFeedback(DragManager.NONE);
                    return;
                }
                trace("allowing drop");
                DragManager.showFeedback(DragManager.MOVE);
            }

            protected function tree_dragDropHandler(event:DragEvent):void {
            }
        ]]>
    </fx:Script>
    <fx:Declarations>
        <fx:XML id="treeData">
            <folder id="root"
                    label="root"
                    type="root">
                <folder id="folder1"
                        label="Folder 1"
                        type="folder">
                    <folder id="folder2"
                            label="Folder 2"
                            type="folder">
                        <item id="item1"
                              label="Item 1"
                              type="item"/>
                        <item id="item2"
                              label="Item 2"
                              type="item"/>
                        <item id="item3"
                              label="Item 3"
                              type="item"/>
                        <item id="item4"
                              label="Item 4"
                              type="item"/>
                        <item id="item5"
                              label="Item 5"
                              type="item"/>
                    </folder>
                </folder>
                <folder id="folder3"
                        label="Folder 3"
                        type="folder"/>
                <folder id="folder4"
                        label="Folder 4"
                        type="folder"/>
                <folder id="folder5"
                        label="Folder 5"
                        type="folder"/>
            </folder>
        </fx:XML>
    </fx:Declarations>
    <mx:Tree id="tree"
             left="29"
             right="28"
             top="28"
             bottom="27"
             dragEnabled="true"
             dropEnabled="true"
             dragMoveEnabled="true"
             dataProvider="{treeData}"
             labelField="@label"
             dragEnter="tree_dragEnterHandler(event)"
             dragOver="tree_dragOverHandler(event)"
             dragDrop="tree_dragDropHandler(event)"
             showRoot="false">
    </mx:Tree>
</s:WindowedApplication>

It's frustrating that the default drag-and-drop functionality almost provides everything necessary to accomplish this, but not quite. It seems that IlyaZ's answer should work, but that may be a bug in Flex's mx:Tree control.

I ended up accomplishing this by rolling my own drag-and-drop implementation as SunilD alluded to. The code is included below for anyone who may run into the same problem in the future.

Note that there's still a small visual feedback issue when the user is dragging over the boundary between maxDropIndex and maxDropIndex+1 : At the lower part of the boundary the drop indicator will shift to indicate that it's possible to drop an item at the folder level. I'm still looking for a good solution to this (can anyone point me to the tree source?).

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
                       xmlns:s="library://ns.adobe.com/flex/spark"
                       xmlns:mx="library://ns.adobe.com/flex/mx"
                       width="354"
                       height="480">
    <fx:Script>
        <![CDATA[
            import mx.collections.ArrayCollection;
            import mx.core.DragSource;
            import mx.core.IUIComponent;
            import mx.core.mx_internal;
            import mx.events.DragEvent;
            import mx.events.FlexEvent;
            import mx.managers.DragManager;

            protected var dragging:Boolean = false;
            protected var minDropIndex:int = 0;
            protected var maxDropIndex:int = 0;

            protected function tree_dragEnterHandler(event:DragEvent):void {
                // only items can be dropped
                if (event.dragSource.hasFormat("tree_item_node")) {
                    DragManager.acceptDragDrop(IUIComponent(event.currentTarget));
                    trace("accepting DragDrop");
                } else {
                    event.preventDefault();
                    DragManager.showFeedback(DragManager.NONE);
                    trace("rejecting DragDrop");
                }
            }

            protected function tree_dragOverHandler(event:DragEvent):void {
                var index:int = tree.calculateDropIndex(event);
                if (index < minDropIndex || index > maxDropIndex) {
                    trace("preventing drop");
                    DragManager.showFeedback(DragManager.NONE);
                    this.tree.hideDropFeedback(event);
                    return;
                }
                trace("allowing drop");
                DragManager.showFeedback(DragManager.MOVE);
                this.tree.showDropFeedback(event);
            }

            protected function tree_dragDropHandler(event:DragEvent):void {
                trace("dragDropHandler");
            }

            protected function tree_mouseMoveHandler(event:MouseEvent):void {
                // see if we should start a drag operation
                if (event.buttonDown && !dragging && tree.selectedItem && tree.selectedItem.@type == "item") {
                    // TODO: calculate the min and max drag indices from currently-selected index
                    minDropIndex = 2;
                    maxDropIndex = 7;

                    // start the drag
                    dragging = true;
                    var dragSource:DragSource = new DragSource();
                    dragSource.addData(tree.selectedItem, "tree_item_node");
                    DragManager.doDrag(IUIComponent(event.currentTarget), dragSource, event);
                }
            }

            protected function tree_dragCompleteHandler(event:DragEvent):void {
                trace("dragComplete: no longer dragging");
                this.tree.hideDropFeedback(event);
                dragging = false;
            }
        ]]>
    </fx:Script>
    <fx:Declarations>
        <fx:XML id="treeData">
            <folder id="root"
                    label="root"
                    type="root">
                <folder id="folder1"
                        label="Folder 1"
                        type="folder">
                    <folder id="folder2"
                            label="Folder 2"
                            type="folder">
                        <item id="item1"
                              label="Item 1"
                              type="item"/>
                        <item id="item2"
                              label="Item 2"
                              type="item"/>
                        <item id="item3"
                              label="Item 3"
                              type="item"/>
                        <item id="item4"
                              label="Item 4"
                              type="item"/>
                        <item id="item5"
                              label="Item 5"
                              type="item"/>
                    </folder>
                </folder>
                <folder id="folder3"
                        label="Folder 3"
                        type="folder"/>
                <folder id="folder4"
                        label="Folder 4"
                        type="folder"/>
                <folder id="folder5"
                        label="Folder 5"
                        type="folder"/>
            </folder>
        </fx:XML>
    </fx:Declarations>
    <mx:Tree id="tree"
             left="29"
             right="28"
             top="28"
             bottom="27"
             dragEnabled="false"
             dropEnabled="false"
             dataProvider="{treeData}"
             labelField="@label"
             dragEnter="tree_dragEnterHandler(event)"
             dragOver="tree_dragOverHandler(event)"
             dragDrop="tree_dragDropHandler(event)"
             dragComplete="tree_dragCompleteHandler(event)"
             mouseMove="tree_mouseMoveHandler(event)"
             showRoot="false">
    </mx:Tree>
</s:WindowedApplication>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM