在Flex 4列表中处理鼠标单击以查找所选项目(因为itemClick已消失)

时间:2011-12-08 15:01:02

标签: flex list flex4 click flex4.5

我为我的问题准备了一个简化的测试用例。如果将下面的2个文件放入项目中,它将立即在Flash Builder中运行。

我正在尝试在弹出窗口中显示字符串列表和确认复选框:

screenshot

在实际应用程序中,我使用列表中选择的字符串调度自定义事件,但在下面的测试代码中,我只调用 trace(str);

我的问题:如果我使用点击事件,那么即使我点击滚动条(!str 检查),窗口也会关闭在以前的使用中选择了一个项目时,下面没有帮助。如果我使用更改事件,那么当我点击与上次相同的项目时,窗口不会关闭。并且 itemClick 事件似乎不再出现在spark.components.List中。

有关如何处理这个可能经常出现的问题的任何建议吗?

为这种情况编写自定义项目渲染器并为每个项目设置单击事件处理程序似乎有点过分,因为我在列表中有字符串。

Test.mxml:(请点击myBtn几次 - 查看点击更改的问题)

<?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="400" minHeight="300">

    <fx:Script>
        <![CDATA[
            import mx.managers.PopUpManager;

            private var _popup:Popup = new Popup();

            private function showPopup(event:MouseEvent):void {
                PopUpManager.addPopUp(_popup, this, true);
                PopUpManager.centerPopUp(_popup);
            }
        ]]>
    </fx:Script>

    <s:Button id="myBtn" right="5" bottom="5" 
        label="Open window" click="showPopup(event)" />

</s:Application>

Popup.mxml:

<?xml version="1.0" encoding="utf-8"?>
<s:TitleWindow 
    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="240" height="240"
    creationComplete="init(event)"
    close="close()">    

    <fx:Script>
        <![CDATA[
            import mx.collections.ArrayList;
            import mx.controls.Alert;
            import mx.events.FlexEvent;
            import mx.events.CloseEvent;
            import mx.events.ItemClickEvent;
            import mx.managers.PopUpManager;

            private var myData:ArrayList = new ArrayList();

            private function init(event:FlexEvent):void {
                // XXX in the real app data is updated from server
                myData.removeAll();
                for (var i:uint = 1; i <= 10; i++)
                    myData.addItem('Item #' + i);
            }

            public function close(event:TimerEvent=null):void {
                PopUpManager.removePopUp(this);
            }

            private function handleClick(event:MouseEvent):void {
                var str:String = myList.selectedItem as String;
                if (!str)
                    return;

                if (myBox.selected) {
                    Alert.show(
                        'Select ' + str + '?', 
                        null, 
                        mx.controls.Alert.YES | mx.controls.Alert.NO,
                        null,
                        handleConfirm,
                        null,
                        mx.controls.Alert.NO
                    );
                } else {
                    sendEvent();
                }
            }

            private function handleConfirm(event:CloseEvent):void {
                if (event.detail == mx.controls.Alert.YES)
                    sendEvent();
            }

            private function sendEvent():void {
                close();
                // XXX in the real app dispatchEvent() is called
                trace('selected: ' + (myList.selectedItem as String));
            }
        ]]>
    </fx:Script>

    <s:VGroup paddingLeft="20" paddingTop="20" 
            paddingRight="20" paddingBottom="20" gap="20" 
            width="100%" height="100%">
        <s:List id="myList" dataProvider="{myData}" 
            click="handleClick(event)"
            width="100%" height="100%" fontSize="24" />
        <s:CheckBox id="myBox" label="Confirm" />
    </s:VGroup>
</s:TitleWindow>

我也想知道,为什么我会收到上面的警告:

Data binding will not be able to detect assignments to "myData".

3 个答案:

答案 0 :(得分:5)

Spark List会调度“IndexChangeEvent。CHANGE”。您可以侦听此事件,以了解列表中的选择何时发生更改。

    <s:List id="myList" dataProvider="{myData}" 
            change="handleIndexChange()"
            width="100%" height="100%" fontSize="24" />

只有在所选索引实际更改时才调度该事件,这意味着当您再次打开窗口时,可能仍然会选择一个项目,当您单击该项目时,将不会触发任何CHANGE事件。要解决此问题,只需在关闭窗口之前取消选择选择:

        public function close():void {
            myList.selectedIndex = -1;
            PopUpManager.removePopUp(this);
        }

另外,请务必在关闭窗口之前使用所选项调度您的事件(并取消选中)。

关于绑定警告的问题:您收到该消息是因为您没有将'myData'标记为可绑定。要解决这个问题,只需使用[Bindable]标签:

[Bindable]
private var myData:ArrayList = new ArrayList();

或者如果你不需要它就完全跳过绑定,只需将数据提供者分配给ActionScript中的列表:

myList.dataProvider = myData;

答案 1 :(得分:2)

如果您绝对想要显示所选项目,我建议使用两种解决方案。否则, RIAStar 提供的解决方案就可以解决问题。

收听PopUp

中的rendererAdd和rendererRemove事件

正如here所述,您可以轻松访问列表的渲染器,而不会干扰其virtualLayout业务。

使用自定义渲染器

我知道。但是只要你保持代码干净,itemRenderers就不会炸毁你的应用程序的内存。它们可以在没有内存泄漏的情况下渲染大量项目。

答案 2 :(得分:-2)

在Test.mxml中,修改如下代码:

  <fx:Script>
            <![CDATA[
                import mx.managers.PopUpManager;

                private var _popup:Popup;

                private function showPopup(event:MouseEvent):void {
                    _popup = new Popup();
                    PopUpManager.addPopUp(_popup, this, true);
                    PopUpManager.centerPopUp(_popup);
                }
            ]]>
        </fx:Script>

在你的Popup.mxml中,我不知道你为什么在关闭函数中有TimerEvent。

此外,跟踪将不会显示,因为您在单击警报的YES按钮后立即调用close()函数。