自定义组件未更新显示列表

时间:2011-07-12 22:51:46

标签: flex flex4 flexbuilder flex4.5

我创建了一个基本上是米的组件(扩展了skinnable容器)。组件的外观包含两个矩形(背景和实际仪表)。该组件接收带有以下字段值,max和min的arraycollection(我传递的arraycollection是Bindable)。当我初始化并传递要用于绘制的数据时它非常有效(请记住 - 仅在第一次工作时)。我创建了一个按钮来更改数据数组并显示当前的仪表值。显然,每当我修改我设置用于渲染的ArrayCollection时,仪表的值都在变化。(不想说“dataProvider”,因为它不是Flex数据提供者,只是一个变量)...这里是代码..

    public class meter extends SkinnableContainer {


    [SkinPart( required = "true" )]
    public var meter:spark.primitives.Rect;

    [SkinPart( required = "true" )]
    public var meterBackground:spark.primitives.Rect;

    private var _dataProvider:ArrayCollection;
    private var _renderDirty:Boolean = false;

    public function Meter() {
        super();
    }

    public function set dataProvider( value:Object ):void {
        if ( value )
        {
            if(value is ArrayCollection)
               {
                   _renderDirty = true;
                _dataProvider = value as ArrayCollection;
               }                
            if(_dataProvider)
            {
                _dataProvider.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, propertyChanged);//used both eventlisteners but none actually ever fire off
                _dataProvider.addEventListener(CollectionEvent.COLLECTION_CHANGE,collectionChanged);
            }
            invalidateDisplayList();//only happens the first time
        }
    }

    private function collectionChanged(event:CollectionEvent):void
    {
        Alert.show("In collection Change");//this never goes off when I change the "dataProvider"
        _renderDirty = true;
        invalidateDisplayList();
    }

    private function propertyChanged(event:PropertyChangeEvent):void
    {
        Alert.show("In property Change");//this never goes off when I change the "dataProvider"
        _renderDirty=true;
         invalidateDisplayList();
    }

    public function get dataProvider():Object {
        return _dataProvider;
    }        

    override protected function updateDisplayList( unscaledWidth:Number, unscaledHeight:Number ):void {


        if(_dataProvider))
        {
        var span:Number = unscaledWidth / _dataProvider[0].max;
        var meterWidth:Number = _dataProvider[0].value * span;

        meter.width = meterWidth;
        _renderDirty = false;
        }

    }

这是我更改“value”字段的mxml代码....

   <fx:Script>
    <![CDATA[
    [Bindable]
        private var meterData:ArrayCollection = new ArrayCollection([                
            {value:80, max:100, min:0}
        ]);

        protected function mySlider_changeHandler(event:Event):void
        {
            meterData[0].value = Math.round(mySlider.value)*10;                
        }

        protected function button1_clickHandler(event:MouseEvent):void
        {
            // TODO Auto-generated method stub
            var array:ArrayCollection = testMeter.dataProvider as ArrayCollection;
            var value:Number = array[0].value as Number;
            Alert.show(value.toString());
           // testMeter.meter.width= Math.random()*100;
        }

    ]]>//initial value in "meterData" does get drawn...but when it's changed with the slider..nothing happens..

   <custom:Meter id="testMeter" dataProvider="{meterData}" /> 
    <s:HSlider id="mySlider" 
               liveDragging="true"
               dataTipPrecision="0" 
               change="mySlider_changeHandler(event)"
               value="3"/>
    <s:Button click="button1_clickHandler(event)"/>

你能帮我弄清楚发生了什么吗?谢谢你们!

1 个答案:

答案 0 :(得分:3)

问题是您没有重置dataProvider,也没有做任何事情来触发collectionChange事件。我会单独处理每一个。以下是重置dataProvider的方法:

testMeter.dataProvider = newDataPRovider;

但是,你不是那样做的。因此set方法永远不会在第一个初始设置之后执行。

如果您需要触发collectionChange事件,则需要更改集合。你实际上并没有这样做。您正在更改集合中的对象。此代码不会更改集合:

meterData[0].value = Math.round(mySlider.value)*10; 

它只更改集合中某个对象的单个属性。尝试这样的事情:

var newObject = meterData[0];
newObject['value'] = Math.round(mySlider.value)*10
meterData.addItem(newObject); 

此代码应触发colletionChange事件,即使您的代码没有。

我还有一些想法,与你的主要问题无关。请务必在dataProvider set方法中删除EventListeners,如下所示:

public function set dataProvider( value:Object ):void {
    if ( value )
    {
// remove the event listeners here before changing the value
// that should allow the object to have no extra 'references' that prevent it from being garbage collected
                _dataProvider.removeEventListener(PropertyChangeEvent.PROPERTY_CHANGE, propertyChanged);
                _dataProvider.removeEventListener(CollectionEvent.COLLECTION_CHANGE,collectionChanged);

            if(value is ArrayCollection)
               {
                   _renderDirty = true;
                _dataProvider = value as ArrayCollection;
               }                
            if(_dataProvider)
            {
                _dataProvider.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, propertyChanged);//used both eventlisteners but none actually ever fire off
                _dataProvider.addEventListener(CollectionEvent.COLLECTION_CHANGE,collectionChanged);
            }
            invalidateDisplayList();//only happens the first time
        }
    }

你说:

  

(不想说“dataProvider”,因为它不是Flex   dataprovider,只是一个变量)

Flex List,DataGrid或DataGroup上的dataProvider也“只是一个变量”。我不认为“Flex框架”的实现与你所做的完全不同,无论如何。由于您特别期望最小值和最大值,因此您应该使用具有这些显式属性的值对象而不是ArrayCollection。