Why are the labels mysteriously dissappearing from a ComboBox in Flex 3?
Observe the Flex program below (I'm using Flex Builder 3 w/ 3.5 SDK). The second combobox is conditional on the first. If a 'first name' is chosen, then you are allowed to choose a 'last name'. If 'none' is chosen, then you are not allowed to choose a last name, but rather prompted to choose a first name.
To see the mysterious issue of the disappearing labels, run this program and choose a first name. Then choose a last name. All is well. Then choose 'none' in the first combobox. The prompt of the second combobox changes back, and the last names are removed. All is still well. Then try selecting a first and last name again. You will see that after choosing a first name, the last names do not appear, although the spaces for them do (and if you debug the program, the correct data appears in the dataprovider).
This 'bug' has been killing me on the inside all day. The project in which I'm implementing this behavior is quite a bit more complex, but this sample basically exemplifies what is going on. Is this a bug in Flex, or am I doing something wrong?
Thanks!
<?xml version="1.0" encoding="utf-8"?>
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
public var cbCompanyDP:ArrayCollection = new ArrayCollection( [ { firstName: "None", data: 0 },
{ firstName: "Bob", data: 1 },
{ firstName: "Bart", data: 2 } ] );
[Bindable]
public var cbEmployeeDP:ArrayCollection = new ArrayCollection();
public var employees:ArrayCollection = new ArrayCollection( [ { lastName: "Smith" },
{ lastName: "Smyth" },
{ lastName: "Smick" },
{ lastName: "Smack" } ] );
[Bindable]
public var prompt:String = "Choose First Name first";
public function cbFirstNameChange( value:int ):void
{
if ( value == 0 )
{
employees.removeAll();
setEmpDP( employees );
prompt = "Choose First Name first";
}
else
{
setEmployees();
setE开发者_如何学CmpDP( employees );
prompt = "Now choose Last Name";
}
}
private function setEmpDP( ac:ArrayCollection ):void
{
cbEmployeeDP = ac;
}
private function setEmployees():void
{
employees = new ArrayCollection( [ { lastName: "Smith" },
{ lastName: "Smyth" },
{ lastName: "Smick" },
{ lastName: "Smack" } ] );
}
]]>
</mx:Script>
<mx:HBox>
<mx:ComboBox dataProvider="{cbCompanyDP}"
id="cbFirstName"
labelField="firstName"
width="200"
change="cbFirstNameChange(cbFirstName.selectedItem.data)"
prompt="Choose a first Name" />
<mx:ComboBox dataProvider="{cbEmployeeDP}"
id="cbLastName"
labelField="lastName"
width="200"
prompt="{prompt}" />
</mx:HBox>
The problem here is that there is a binding missing. If you change the dataProvider of teh ComboBox, it does not change the dataProvider of the generated dropdown. So the box knows the new list, but the dropdown still handles the old. To fix this, you have to subclass the ComboBox and override set dataProvider and get dataProvider (for symmetry).
override protected function set dataProvider (value:Object):void {
super.dataProvider=value;
if(dropdown != null)
super.dropdown.dataProvider=value;
}
To also update the width of the dropdown in case the ComboBox width changed, it is also necessary to override another function:
override protected function updateDisplayList
( unscaledWidth:Number, unscaledHeight:Number ):void {
super.updateDisplayList (unscaledWidth, unscaledHeight);
if (dropdown != null)
dropdown.width = unscaledWidth;
}
This way it works as it should. if you want, you can in the set dunction check whether the selectedIndex is -1 (which on an editable box means that there is manually entered content), save it from super.text and restore it to super.text (and set the index to -1 again) once you have set the new dataProvider. Else the text in the input field will be lost or replaced by the first list element.
do not set new ArrayCollection to dataProvider in Flex 3.5, if data provider was already set - set dataProvider.source (to not make new reference)
I had the same problem just yesterday. It seems to be a bug in 3.5. It happens when you assign a new ArrayCollection object to the one binded in combobox. If you click in the combo box it will refresh, and show the real content.
The solution to this in 3.5: do not assign a new arraycollection to the binded variable. You should only set the source as said by anton, or utilize the add/remove/addAll Item methods.Something like this should work too:
private function setEmpDP( ac:ArrayCollection ):void
{
cbEmployeeDp.removeAll();
cbEmployeeDP.addAll(ac);
}
I tried with a different SDK (3.2 and 4) and it is working on, so I guess it is a bug from 3.5
Well it appears there are two answers: Yes, this is a bug in Flex 3.5 sdk, as it does not happen in 4 (I have not tested with other SDKs). However, since I cannot change SDKs mid-project, the workaround appeared in another question: Flex 3.5.0; Update ComboBox display list upon dataprovider change
Thanks for everyone's input.
精彩评论