Пользовательский компонент не обновляет список отображения - PullRequest
1 голос
/ 13 июля 2011

Я создал компонент, который в основном является метром (расширяет контейнер для скинов).Скин для компонента содержит два прямоугольника (фон и фактический метр).Этот компонент получает коллекцию массивов со следующими значениями полей, max и min (коллекция массивов, которую я передаю, является 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;
        }

    }

И это код 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 Ответ

3 голосов
/ 13 июля 2011

Проблема в том, что вы не сбрасываете 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, даже если у вас этого кода нет.

У меня есть еще несколько мыслей, не связанных с вашим основным вопросом.Обязательно удалитеEventListeners в методе набора данных dataProvider, например:

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 также является «просто переменной».Я не вижу, как реализация «Flex Framework» так сильно отличается от того, что вы делали, в любом случае концептуально.Поскольку вы конкретно ожидаете минимальное и максимальное значения, возможно, вам следует использовать объект значения с этими явными свойствами вместо ArrayCollection.

...