在Flex ComboBox中为空

Wou*_*rts 3 apache-flex null combobox

如何制作用户可以选择的ComboBox null

如果您只是在数据提供者null中创建一个组合框,则会显示该值,但用户无法选择它:

<mx:ComboBox id="cb" dataProvider="{[null, 'foo', 'bar']}" />
Run Code Online (Sandbox Code Playgroud)

有没有办法让null可选?

解决方法是将一个项添加到dataProvider中,该项不是null但是'表示'为null; 然后每次访问组合框时在null和该对象之间进行映射.但这不是一个优雅的解决方案; 在访问'可空'组合框的所有代码中,你总是要记住这个映射...

编辑:扩展为什么我不喜欢变通方法:当然可以在子类中完成,但要么我引入新属性(如nullableSelectedItem); 但是你必须小心,始终使用这些属性.或者我覆盖ComboBoxes selectedItem; 但是我很害怕打破基类:它可能不喜欢改变它对当前所选项目的内容的想法.即使这个脆弱的破解工作,在顶部selectedItemdataProvider那么这个nullItem也需要进行处理的特殊datalistData用于渲染,在labelFunction,然后它可能仍然在事件暴露了组合框发送...这可能会奏效,但它是一个相当hack只是为了解决这个问题:如果用户点击它没有激活它的项目(其余的则ComboBox处理null罚款).(另一个替代方案是将一个ui组件委托给ComboBox,但是为了避免这个小问题,甚至还有更多的代码)

Cos*_*hia 5

似乎正确管理空项目的唯一方法是将项目实际添加到组合框的数据提供者中.以下子类将自动处理此问题.

实现有点棘手,以支持对数据提供者的更改,包括项目添加/删除以及数据提供者本身的完全重新分配(只需考虑与远程服务响应的arraycollections绑定).

package {

    import flash.events.Event;
    import flash.events.FocusEvent;
    import mx.collections.ArrayCollection;
    import mx.collections.ICollectionView;
    import mx.collections.IList;
    import mx.containers.FormItem;
    import mx.controls.ComboBox;
    import mx.events.CollectionEvent;
    import mx.events.ListEvent;
    import mx.validators.Validator;

    public class EmptyItemComboBox extends ComboBox {

        protected var _emptyItem:Object = null;
        protected var _originalDataProvider:ICollectionView = null;

        public function EmptyItemComboBox() {
            super();
            addEmptyItem();
            addEventListener(Event.CHANGE, onChange);
        }

        private function onChange(event:Event):void {
            dispatchEvent(new Event("isEmptySelectedChanged"));
        }

        [Bindable]
        public function get emptyItem():Object {
            return _emptyItem;
        }

        public function set emptyItem(value:Object):void {
            if (_emptyItem != value) {
                clearEmptyItem();
                _emptyItem = value;
                addEmptyItem();
            }
        }

        [Bindable(event="isEmptySelectedChanged")]
        public function get isEmptySelected():Boolean {
                return (selectedItem == null || (_emptyItem != null && selectedItem == _emptyItem));
        }

        override public function set selectedItem(value:Object):void {
            if (value == null && emptyItem != null) {
                super.selectedItem = emptyItem;
            } else    if (value != selectedItem) {
                super.selectedItem = value;
            }
            dispatchEvent(new Event("isEmptySelectedChanged"));
        }

        override public function set dataProvider(value:Object):void {
            if (_originalDataProvider != null) {
                _originalDataProvider.removeEventListener(
                        CollectionEvent.COLLECTION_CHANGE,
                        onOriginalCollectionChange);
            }
            super.dataProvider = value;
            _originalDataProvider = (dataProvider as ICollectionView);
            _originalDataProvider.addEventListener(
                    CollectionEvent.COLLECTION_CHANGE,
                    onOriginalCollectionChange)
            addEmptyItem();
        }

        private function clearEmptyItem():void {
            if (emptyItem != null && dataProvider != null 
                    && dataProvider is IList) {
                var dp:IList = dataProvider as IList;
                var idx:int = dp.getItemIndex(_emptyItem);
                if (idx >=0) {
                    dp.removeItemAt(idx);    
                }
            }
            dispatchEvent(new Event("isEmptySelectedChanged"));
        }

        private function addEmptyItem():void {
            if (emptyItem != null) {
                 if (dataProvider != null && dataProvider is IList) {
                    var dp:IList = dataProvider as IList;
                    var idx:int = dp.getItemIndex(_emptyItem);
                    if (idx == -1) {
                        var newDp:ArrayCollection = new ArrayCollection(dp.toArray().concat());
                        newDp.addItemAt(_emptyItem, 0);
                        super.dataProvider = newDp;
                    }
                }
            }
            dispatchEvent(new Event("isEmptySelectedChanged"));
        }

        private function onOriginalCollectionChange(event:CollectionEvent):void {
            if (_emptyItem != null) {
                dataProvider = _originalDataProvider;
                addEmptyItem();
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

    <mx:Script>
    <![CDATA[
        import mx.controls.Alert;
    ]]>
    </mx:Script>

    <mx:ArrayCollection id="myDP">
    <mx:source>
        <mx:Array>
            <mx:Object value="1" label="First"/>  
            <mx:Object value="2" label="Second"/>
            <mx:Object value="3" label="Third"/>
        </mx:Array>
    </mx:source>
    </mx:ArrayCollection>

    <local:EmptyItemComboBox id="comboBox" dataProvider="{myDP}" labelField="label">
    <local:emptyItem>
        <mx:Object value="{null}" label="(select an item)"/>  
    </local:emptyItem>
    </local:EmptyItemComboBox>

    <mx:Button label="Show selected item" click="Alert.show(comboBox.selectedItem.value)"/>

    <mx:Button label="Clear DP" click="myDP.removeAll()"/>
    <mx:Button label="Add item to DP" click="myDP.addItem({value: '4', label: 'Fourth'})"/>
    <mx:Button label="Reset DP" click="myDP = new ArrayCollection([{value: '1', label: 'First'}])"/>

    <mx:Label text="{'comboBox.isEmptySelected = ' + comboBox.isEmptySelected}"/>

</mx:Application>
Run Code Online (Sandbox Code Playgroud)

package {

    import flash.events.Event;
    import flash.events.FocusEvent;
    import mx.collections.ArrayCollection;
    import mx.collections.ICollectionView;
    import mx.collections.IList;
    import mx.containers.FormItem;
    import mx.controls.ComboBox;
    import mx.events.CollectionEvent;
    import mx.events.ListEvent;
    import mx.validators.Validator;

    public class EmptyItemComboBox extends ComboBox {

        protected var _emptyItem:Object = null;
        protected var _originalDataProvider:ICollectionView = null;

        public function EmptyItemComboBox() {
            super();
            addEmptyItem();
            addEventListener(Event.CHANGE, onChange);
        }

        private function onChange(event:Event):void {
            dispatchEvent(new Event("isEmptySelectedChanged"));
        }

        [Bindable]
        public function get emptyItem():Object {
            return _emptyItem;
        }

        public function set emptyItem(value:Object):void {
            if (_emptyItem != value) {
                clearEmptyItem();
                _emptyItem = value;
                addEmptyItem();
            }
        }

        [Bindable(event="isEmptySelectedChanged")]
        public function get isEmptySelected():Boolean {
                return (selectedItem == null || (_emptyItem != null && selectedItem == _emptyItem));
        }

        override public function set selectedItem(value:Object):void {
            if (value == null && emptyItem != null) {
                super.selectedItem = emptyItem;
            } else    if (value != selectedItem) {
                super.selectedItem = value;
            }
            dispatchEvent(new Event("isEmptySelectedChanged"));
        }

        override public function set dataProvider(value:Object):void {
            if (_originalDataProvider != null) {
                _originalDataProvider.removeEventListener(
                        CollectionEvent.COLLECTION_CHANGE,
                        onOriginalCollectionChange);
            }
            super.dataProvider = value;
            _originalDataProvider = (dataProvider as ICollectionView);
            _originalDataProvider.addEventListener(
                    CollectionEvent.COLLECTION_CHANGE,
                    onOriginalCollectionChange)
            addEmptyItem();
        }

        private function clearEmptyItem():void {
            if (emptyItem != null && dataProvider != null 
                    && dataProvider is IList) {
                var dp:IList = dataProvider as IList;
                var idx:int = dp.getItemIndex(_emptyItem);
                if (idx >=0) {
                    dp.removeItemAt(idx);    
                }
            }
            dispatchEvent(new Event("isEmptySelectedChanged"));
        }

        private function addEmptyItem():void {
            if (emptyItem != null) {
                 if (dataProvider != null && dataProvider is IList) {
                    var dp:IList = dataProvider as IList;
                    var idx:int = dp.getItemIndex(_emptyItem);
                    if (idx == -1) {
                        var newDp:ArrayCollection = new ArrayCollection(dp.toArray().concat());
                        newDp.addItemAt(_emptyItem, 0);
                        super.dataProvider = newDp;
                    }
                }
            }
            dispatchEvent(new Event("isEmptySelectedChanged"));
        }

        private function onOriginalCollectionChange(event:CollectionEvent):void {
            if (_emptyItem != null) {
                dataProvider = _originalDataProvider;
                addEmptyItem();
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

    <mx:Script>
    <![CDATA[
        import mx.controls.Alert;
    ]]>
    </mx:Script>

    <mx:ArrayCollection id="myDP">
    <mx:source>
        <mx:Array>
            <mx:Object value="1" label="First"/>  
            <mx:Object value="2" label="Second"/>
            <mx:Object value="3" label="Third"/>
        </mx:Array>
    </mx:source>
    </mx:ArrayCollection>

    <local:EmptyItemComboBox id="comboBox" dataProvider="{myDP}" labelField="label">
    <local:emptyItem>
        <mx:Object value="{null}" label="(select an item)"/>  
    </local:emptyItem>
    </local:EmptyItemComboBox>

    <mx:Button label="Show selected item" click="Alert.show(comboBox.selectedItem.value)"/>

    <mx:Button label="Clear DP" click="myDP.removeAll()"/>
    <mx:Button label="Add item to DP" click="myDP.addItem({value: '4', label: 'Fourth'})"/>
    <mx:Button label="Reset DP" click="myDP = new ArrayCollection([{value: '1', label: 'First'}])"/>

    <mx:Label text="{'comboBox.isEmptySelected = ' + comboBox.isEmptySelected}"/>

</mx:Application>
Run Code Online (Sandbox Code Playgroud)