在我使用 Flex 构建的应用程序中,我有一个以 XML 作为其数据提供者的 Flex 树。用户需要能够创建图层和文件夹来保存这些图层(想想 Photoshop)。用户还需要能够随意重新排列这些项目,并将图层拖到文件夹中(如果需要,还可以将文件夹拖到其他文件夹中,等等)。
这是我制作的一个测试应用程序,展示了我正在尝试做的事情。为简单起见,我已将其简化为尽可能基本。
(注意:我在我的代码中创建带有一个虚拟节点的 XML,然后在运行时删除该节点。这是我发现的唯一方法,它会使 Tree 在启动时完全空白。(只是有一个空的根节点会导致该根节点在树中可见,即使 showRoot 为 false。)如果有更好的方法来实现该效果,请告诉我。)
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600">
<fx:Script>
<![CDATA[
import com.custom.model.service.XMLService;
import mx.events.DragEvent;
import mx.events.FlexEvent;
import mx.utils.ObjectUtil;
protected function treeInit(event:FlexEvent):void
{
layersTree.expandChildrenOf(layers_xml, true);
/*delete the dummy XML node so that the tree is clean on startup
and doesn't show the root folder*/
XMLService.deleteNodeById(layers_xml, 'dummy');
}
protected function newFolderClick(event:MouseEvent):void
{
// Form New XML Node..
var xmlObj:Object = XMLService.formFolderXML();
//...and add it to the XML file.
if(!layers_xml.children()[0]){
//if there are no child nodes, add normally
layers_xml.source = xmlObj.xmlNode;
}else{
//if there are child nodes, add them before the previous node
layers_xml.prependChild(xmlObj.xmlNode);
}
/*immediately expand the folders to allow them to be dragged into,
closed folders cannot be dragged into*/
layersTree.expandChildrenOf(layers_xml, true);
}
protected function newTextLayerClick(event:MouseEvent):void
{
// Form New XML Node..
var xmlObj:Object = XMLService.formTextLayerXML();
//...and add it to the XML file.
if(!layers_xml.children()[0]){
//if there are no child nodes, add normally
layers_xml.source = xmlObj.xmlNode;
}else{
//if there are child nodes, add them before the previous node
layers_xml.prependChild(xmlObj.xmlNode);
}
//programatically select THIS item so it highlights in the tree
layersTree.selectedIndex = (layersTree.showRoot) ? 1 : 0;
}
protected function onDragDrop(event:DragEvent):void
{
trace('action:', event.action);
trace('dragDrop', ObjectUtil.toString(layers_xml));
}
protected function onDragComplete(event:DragEvent):void
{
trace('action:', event.action);
trace('dragComplete', ObjectUtil.toString(layers_xml));
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
<fx:XML id="layers_xml">
<layers label="root" id="root">
<layer label="DummyLayer2" type="layer" id="dummy" isVisible="false" />
</layers>
</fx:XML>
</fx:Declarations>
<s:VGroup gap="0" width="100%">
<mx:Tree id="layersTree" width="100%" minHeight="41" allowMultipleSelection="false"
borderVisible="false" creationComplete="treeInit(event)"
dataProvider="{layers_xml}" dragEnabled="true" dropEnabled="true"
focusColor="#FFFFFF" labelField="@label"
rollOverColor="#D1EEEE" selectionColor="#D1EEEE" showRoot="false"
dragDrop="onDragDrop(event)" dragComplete="onDragComplete(event)"/>
<s:Group width="100%">
<s:HGroup id="layerButtons" horizontalCenter="0">
<s:Button id="newFolderBtn" label="Folder" buttonMode="true"
click="newFolderClick(event)"/>
<s:Button id="newTextFieldBtn" label="TextLayer" buttonMode="true"
click="newTextLayerClick(event)" />
</s:HGroup>
</s:Group>
</s:VGroup>
</s:Application>
这是我用来生成要插入到树中的 XML 节点的类 (XMLService)。
package com.custom.model.service
{
import flash.events.EventDispatcher;
import flash.events.IEventDispatcher;
public class XMLService extends EventDispatcher
{
private static var _folderLayerCount:int = 0;
private static var _textLayerCount:int = 0;
private static var _layerName:String;
private static var _layerId:String;
public function XMLService(target:IEventDispatcher=null)
{
super(target);
}
private static function randomId(length:int = 9):String{
//function to generate randomId for XML
var chars:String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
var num_chars:Number = chars.length - 1;
var randomChar:String = "";
for (var i:Number = 0; i < length; i++){
randomChar += chars.charAt(Math.floor(Math.random() * num_chars));
}
return randomChar;
}
public static function formTextLayerXML(name:String = null):Object {
//this static function forms the xml node for text layers.
_textLayerCount++;
_layerId = randomId();
_layerName = (name != null) ? name : ('Text Layer ' + _textLayerCount);
var textNode:XML = new XML('<layer label="' + _layerName + '" type="textlayer" id="'+ _layerId +'" isVisible="true" />');
//returns the node and the unique id as a string
return {xmlNode : textNode, id : _layerId};
}
public static function formFolderXML():Object {
//this static function forms the xml node for folders.
_folderLayerCount++;
_layerId = randomId();
_layerName = 'Folder ' + _folderLayerCount;
var folderNode:XML = new XML('<folder label="' + _layerName + '" type="folder" id="'+ _layerId +'" isBranch="true" isVisible="true" />');
//isBranch = true makes the node behave as a folder, even if it's empty
//returns the node and the unique id as a string
return {xmlNode: folderNode, id: _layerId};
}
public static function deleteNodeById(xml:XML, idToDelete:String):void {
var count:int = 0; /*have to keep track of our own count
because targeting will not work for xml deletes */
var descendNodes:XMLList = xml.descendants();
for each (var layer:XML in descendNodes) {
if(descendNodes[count].@id == idToDelete) {
delete descendNodes[count];
}
count++;
}
}
}
}
我遇到的问题是,当创建文件夹和图层并将图层拖入文件夹时,一旦将该文件夹拖出文件夹,就会创建图层的副本而不是移动图层。
动态创建的文件夹和图层:
在文件夹内拖动一个图层:
如果现在将图层拖到文件夹外部(及上方)会发生什么情况:
当在 dragComplete 上跟踪 layers_xml 时,您可以在 XML 中看到这种情况。
<layers label="root" id="root">
<layer label="Text Layer 1" type="textlayer" id="GMccFXr5m" isVisible="true"/>
<folder label="Folder 1" type="folder" id="JfoN1yo1I" isBranch="true" isVisible="true">
<layer label="Text Layer 1" type="textlayer" id="GMccFXr5m" isVisible="true"/>
</folder>
</layers>
“文件夹 1”中的文本层(“文本层 1”)被复制到文件夹节点之外,而不是移动到文件夹节点之外。
现在这是奇怪的部分。
如果在 Tree Flex 组件中将 showRoot 设置为 true,此问题就会消失。问题是在树中可见的根节点是不可取的。
我们对 Tree 组件进行了这个小改动:
showRoot="true"
如果在 showRoot 为真时采取了相同的步骤,现在看看正在跟踪的 layers_xml:
<layers label="root" id="root">
<layer label="Text Layer 1" type="textlayer" id="nwdwAwlML" isVisible="true"/>
<folder label="Folder 1" type="folder" id="TdVbaPvPB" isBranch="true" isVisible="true"/>
</layers>
我在 Flex 中遇到过错误吗?或者我的代码中有什么导致这种情况发生?
虽然感谢任何回应或解释为什么会发生这种情况,但建议我使用除 XML 之外的任何类型的 dataProvider 的答案不会有太大帮助,因为我正在使用它构建的应用程序离最后阶段太远了做出如此剧烈的改变。
谢谢您的帮助!