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

发布于 2024-11-20 00:22:13 字数 3521 浏览 3 评论 0原文

我创建了一个基本上是一个仪表的组件(扩展了可换肤容器)。组件的外观包含两个矩形(背景和实际仪表)。该组件接收具有以下字段值、最大值和最小值的数组集合(我传递的数组集合是可绑定的)。当我初始化并传递用于绘制的数据时,它效果很好(请记住 - 仅在第一次时有效)。我创建了一个按钮来更改数据数组并显示当前的仪表值。显然,每次我修改设置用于渲染的 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)"/>

您能帮我弄清楚发生了什么吗?谢谢大家!!!

I've created a component which is basically a meter (extends skinnable container). The skin to the component contains two rectangles (background and the actual meter). This component receives an arraycollection with the following fields value, max and min(the arraycollection I am passing is Bindable). When I initialize and pass the data to be used to draw It works great (keep in mind - only works the first time). I've created a button that changes the data array and shows the current meter value. Apparently the meter's value is changing everytime I modify the ArrayCollection I've set to be used for rendering.(dont want to say "dataProvider" because it is not a Flex dataprovider, just a variable )... here is the code...

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

    }

And this is the mxml code where I change the "value" field....

   <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)"/>

Can you help me figure out what's going on??Thanks guys!!!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

困倦 2024-11-27 00:22:13

问题是您没有重置 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 Framework”实现与您所做的有什么不同。由于您特别期望最小值和最大值,也许您应该使用具有这些显式属性的值对象而不是 ArrayCollection。

The issue is that you are not resetting the dataProvider, nor doing anything to fire off a collectionChange event. I'll deal with each one individually. Here is how you reset the dataProvider:

testMeter.dataProvider = newDataPRovider;

But, you aren't doing that. So the set method will never execute after the first initial set.

If you need the collectionChange event to fire, you need to change the collection. You aren't actually doing that. You are changing the object in the collection. This code does not change the collection:

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

It just changes a single property in one of the objects of the collection. Try something like this:

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

This code should fire off the colletionChange event, even though the code you have does not.

I have a few more thoughts, unrelated to your primary question. Be sure to removeEventListeners in the dataProvider set method, like this:

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

And you said:

(dont want to say "dataProvider" because it is not a Flex
dataprovider, just a variable )

A dataProvider on the Flex List, or DataGrid, or DataGroup is also "just a variable." I don't see how the "Flex Framework" implementation is all that different than what you've done, conceptually anyway. Since you're specifically expecting a min and max value perhaps you should use a Value Object with those explicit properties instead of an ArrayCollection.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文