繁体   English   中英

在Flex ComboBox中为空

[英]Null in Flex ComboBox

如何创建一个用户可以选择null的ComboBox?

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

<mx:ComboBox id="cb" dataProvider="{[null, 'foo', 'bar']}" />

有没有办法让null可选?

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

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

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

实现有点棘手,以支持对数据提供者的更改,包括项目添加/删除以及数据提供者本身的完全重新分配(只需考虑与远程服务响应的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(); } } } } 

关于班级的一些注意事项:

  • 它会自动在列表中插入空对象..这是我的场景的一个强烈要求:数据提供者是由远程服务返回的,他们不能包含其他元素只是为了支持Flex UI,我也不能手动观看每个集合在每个集合刷新上创建空项。

  • 由于它必须处理集合的内容,因此它将在内部创建具有相同项目实例和空项目的原始副本的副本,因此原始集合的实例根本不会被触及并且可以重复使用在其他方面。

  • 它将监听原始数据提供者的更改,允许对其进行处理甚至分配一个合适的新数据:空项将自动重新创建。

  • 您可以使用emptyItem属性将实际实例用作“空项”:这允许与集合的其余部分保持一致的数据类型(如果使用类型化对象),或者在上面定义自定义标签它。

一些使用它的示例代码......

  <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> 

以下解决方案可能是最简单的解决方案:

<mx:ComboBox id="cb" dataProvider="{[{label:"", data:null}, {label:'foo', data:'foo'}, {label:'bar', data:'bar'}]}" />

并使用cb.selectedItem.data访问数据

然而,正如Wouter所提到的,这个简单的解决方案并不具有约束力。

所以这是一个更棘手的解决方案,允许选择空对象

<mx:ComboBox id="cb" dataProvider="{[null, 'foo', 'bar']}" dropdownFactory="{new ClassFactory(NullList)}" />

NullList是以下类:

package test
{
import mx.controls.List;

public class NullList extends List
{
    public function NullList()
    {
        super();
    }

    override public function isItemSelectable(data:Object):Boolean
    {
        if (!selectable)
            return false;
        return true;
    }

}
}

不幸的是,这是不可能的。 但是,一个不会让你“必须记住这个映射”的好解决方案是创建一个继承自ComboBox的类,它具有自己的DataProvider属性。

这个属性setter将处理null值并在超级ComboBox类上有一个表示。

requireSelection =“false”将允许空值和提示允许您输入该空白值的文本用途(如果您愿意)。

一个非常简单但也非常有限的解决方案是添加一个prompt =“”属性。

这将阻止ComboBox自动选择dataProvider中的第一个项目,但只要用户选择一个项目,就不会再显示空行。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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