Flex:preventDefault on spark:ListBase无效

时间:2012-10-03 21:04:14

标签: actionscript-3 flex preventdefault

我想要实现的建议用户体验是这样的:

  1. 用户单击菜单项(通过listBase子类:例如ButtonBar或TabBar)
  2. 阻止初选
  3. 验证用户是否需要解决问题(例如表单上未保存的数据等)
  4. 如果有效,请选择并将listBase设置为selectedIndex,否则向用户显示警告并完全取消选择过程
  5. 这不会像您期望的那样有效。利用IndexChangeEvent.CHANGING类型和preventDefault可以终止选择,但是在步骤4,当我以编程方式设置listBase的selectedIndex时,它会尝试重新调度CHANGING事件(尽管API文档声称这是什么)。 / p>

    如果您想亲自尝试,请参阅示例应用程序src代码。我期待着你的评论和的解决方案。

    感谢。 Ĵ

    http://snipt.org/vUji3#expand

    <?xml version="1.0" encoding="utf-8"?>
    <s:Application minWidth="955" minHeight="600"
               xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:mx="library://ns.adobe.com/flex/mx"
               xmlns:s="library://ns.adobe.com/flex/spark">
    <fx:Script>
        <![CDATA[
            import flash.utils.setTimeout;
    
            import mx.core.mx_internal;
    
            import spark.events.IndexChangeEvent;
    
            use namespace mx_internal;
    
            [Bindable]
            private var doPreventDefault:Boolean;
    
            [Bindable]
            private var delayMS:uint = 500;
    
            private function buttonbar_changingHandler( event:IndexChangeEvent ):void
            {
                // TODO Auto-generated method stub
                if ( doPreventDefault )
                {
                    event.preventDefault();
    
                    setTimeout( delayedLogic, delayMS, event.newIndex );
                }
            }
    
            private function delayedLogic( index:int ):void
            {
                //disabling this results in an endless loop of trying to set the selected index
                //              doPreventDefault = false;
    
                //this should NOT be hitting the changing handler since we're supposed to be dispatching a value commit event instead.
                bb.setSelectedIndex( index, false );
            }
        ]]>
    </fx:Script>
    
    <fx:Declarations>
    
        <!-- Place non-visual elements (e.g., services, value objects) here -->
    </fx:Declarations>
    
    <s:layout>
        <s:VerticalLayout horizontalAlign="center"/>
    </s:layout>
    
    <s:ButtonBar id="bb"
                 changing="buttonbar_changingHandler(event)">
        <s:dataProvider>
            <s:ArrayList>
                <fx:String>btn 0</fx:String>
                <fx:String>btn 1</fx:String>
                <fx:String>btn 2</fx:String>
            </s:ArrayList>
        </s:dataProvider>
    </s:ButtonBar>
    
    <s:CheckBox label="preventDefault?"
                selected="@{ doPreventDefault }"/>
    
    <s:NumericStepper maximum="5000" minimum="500"
                      stepSize="500" value="@{ delayMS }"/>
    </s:Application>
    

1 个答案:

答案 0 :(得分:1)

看看SDK,IndexChangeEvent.CHANGING事件实际上是可以预防的 - 尽管文档here说可取消是假的,所以我的不好(虽然ASDoc有点横向),但事情得到了解决从这里开始有点有趣。

在ListBase @ 1296中,只能从commitSelection(dispatchEvents:Boolean = true)方法调度。在ButtonBarBase:dataProvider_changeHandler()中唯一一个专门调用不调度事件的地方,但在ListBase中,当有一个proposedSelectionIndex时,它会在commitProperties @ 939中调用。

因此,从上面的代码中,如果您尝试设置选择 - 这将调用commitSelection,我认为这会导致调用堆栈问题。定时器延迟只会加剧这个问题,因为在500ms时,UI将至少经历一次无效循环,这意味着由于invalidateProperties标志正在设置proprosedSelectionIndex,因此将再次执行commitSelection。 1}}最终源于setSelectedIndex @ 729

那么如何解决这个问题。
如果验证失败,我会考虑只做防止,否则允许它正常进行。如果失败,请调用prevent,设置errorString或等效,但不要尝试更改选择。

[编辑]阅读RiaStar的评论,我刚才同意“解决方案”。