删除ItemRenderer中的Button,给出错误

时间:2011-06-20 13:36:54

标签: flex flex4 action itemrenderer

我使用以下.as文件作为列表中itemrenderer的组件。基本上每个项目都在TextInput中呈现,每个TextInput都有一个删除按钮,您可以从代码中看到。单击删除按钮时,我想删除selectedItem..so我将函数removeItem()放在MainMxml.xml中并从.as文件中调用它。

但是我收到错误“无法访问空对象引用的方法或属性”。你能帮我解决这个错误吗?

.as文件如下:

package components {
    import flash.events.Event;
    import flash.events.MouseEvent;

    import mx.events.FlexEvent;

    import renderers.TextInputRenderer;

    import spark.components.Button;
    import spark.components.TextInput;
    import spark.events.TextOperationEvent;

    public class ClearableTextInput extends TextInput {

        [SkinPart(required="true")]
        public var clearButton:Button;

        [Bindable]
        public var mainMxml:MainMxml;


        public function ClearableTextInput() {
            super();

            //watch for programmatic changes to text property
            this.addEventListener(FlexEvent.VALUE_COMMIT, textChangedHandler, false, 0, true);

            //watch for user changes (aka typing) to text property
            this.addEventListener(TextOperationEvent.CHANGE, textChangedHandler, false, 0, true);
        }

        private function textChangedHandler(e:Event):void {
            if (clearButton) {
                clearButton.visible = (text.length > 0);
            }
        }

        private function clearClick(e:MouseEvent):void {
            mainMxml.removeItem();


        }


        override protected function partAdded(partName:String, instance:Object):void {
            super.partAdded(partName, instance);

            if (instance == clearButton) {
                clearButton.addEventListener(MouseEvent.CLICK, clearClick);
                clearButton.visible = (text != null && text.length > 0);
            }           
        }

        override protected function partRemoved(partName:String, instance:Object):void {
            super.partRemoved(partName, instance);

            if (instance == clearButton) {
                clearButton.removeEventListener(MouseEvent.CLICK, clearClick);
            }

        }
    }
}

ItemRenderer就是这样:

<?xml version="1.0" encoding="utf-8"?>
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" 
                xmlns:s="library://ns.adobe.com/flex/spark" 
                xmlns:mx="library://ns.adobe.com/flex/mx" 
                autoDrawBackground="true" xmlns:components="components.*" width="100%">

    <s:layout> 
        <s:HorizontalLayout/> 
    </s:layout> 

    <fx:Script>
        <![CDATA[
            import mx.core.EdgeMetrics;
            import mx.core.UIComponent;

            import skins.ClearableTextInputSkin;

        ]]>
    </fx:Script>


    <components:ClearableTextInput id="clearTxt" text="{data.label}" skinClass="skins.ClearableTextInputSkin" />

</s:ItemRenderer>

我也在ClearableTextInputSkin中设置了清除按钮,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<s:SparkSkin
        xmlns:fx="http://ns.adobe.com/mxml/2009"
        xmlns:s="library://ns.adobe.com/flex/spark"
        minWidth="100" minHeight="22"
        alpha.disabled="0.5"
        blendMode="normal">

    <fx:Metadata>
        [HostComponent("components.ClearableTextInput")]
    </fx:Metadata> 

    <!-- states -->
    <s:states>
        <s:State name="normal"/>
        <s:State name="disabled"/>
    </s:states>

    <!-- bg --> 
    <s:Rect id="border" left="0" right="0" top="0" bottom="0" radiusX="3">
        <s:fill>
            <s:SolidColor id="bgFill" color="#ffffff" />
        </s:fill>
        <s:stroke>
            <s:SolidColorStroke id="borderStroke" color="#333333" weight="1" />
        </s:stroke>
    </s:Rect>

    <!-- text -->
    <s:RichEditableText id="textDisplay" left="4" right="24" top="1" bottom="0"
            color="#333333"
            verticalAlign="middle" />



    <s:Button id="clearButton" right="4" verticalCenter="0" />

</s:SparkSkin>

非常感谢您的帮助。

非常感谢。

1 个答案:

答案 0 :(得分:1)

答案可能非常长:)

从代码开始,问题就在于:

mainMxml.removeItem();

您的mainMxml实例为null,这就是您拥有NPE(空指针异常)的原因。

但是代码一般表明您目前不了解Flex,尤其是数据绑定。当然还有app的架构问题。

首先,你的行:

[Bindable]
public var mainMxml:MainMxml;

什么都不做。

数据绑定只是一种监听带有[Bindable]元标记的变量的变化的方法。 [Bindable]不是一种依赖注入,而是完全相反的。

所以没有人设置mainMxml字段的值。说实话,这不是尝试在那里注入价值的正确方法。取而代之的是,您应该使用Observer design pattern并从组件中触发事件:

package events {
    public class ClearableTextInputEvent extends Event {
        public static const PERFORM_CLEAR:String = "performClear";
        public function ClearableTextInputEvent(type:String) {
            super(type);
        }

    }
}

现在是组件:

package components {
    import flash.events.Event;
    import flash.events.MouseEvent;

    import mx.events.FlexEvent;

    import renderers.TextInputRenderer;

    import spark.components.Button;
    import spark.components.TextInput;
    import spark.events.TextOperationEvent;

    [Event(name="performClear", type="events.ClearableTextInputEvent")]
    public class ClearableTextInput extends TextInput {

        [SkinPart(required="true")]
        public var clearButton:Button;

        public function ClearableTextInput() {
            super();

            //watch for programmatic changes to text property
            this.addEventListener(FlexEvent.VALUE_COMMIT, textChangedHandler, false, 0, true);

            //watch for user changes (aka typing) to text property
            this.addEventListener(TextOperationEvent.CHANGE, textChangedHandler, false, 0, true);
        }

        private function textChangedHandler(e:Event):void {
            if (clearButton) {
                clearButton.visible = (text.length > 0);
            }
        }

        private function clearClick(e:MouseEvent):void {
            dispatchEvent(new ClearableTextInputEvent(ClearableTextInputEvent.PERFORM_CLEAR));
        }


        override protected function partAdded(partName:String, instance:Object):void {
            super.partAdded(partName, instance);

            if (instance == clearButton) {
                clearButton.addEventListener(MouseEvent.CLICK, clearClick);
                clearButton.visible = (text != null && text.length > 0);
            }           
        }

        override protected function partRemoved(partName:String, instance:Object):void {
            super.partRemoved(partName, instance);

            if (instance == clearButton) {
                clearButton.removeEventListener(MouseEvent.CLICK, clearClick);
            }

        }
    }
}

确定。现在我们的渲染器。我们应该使用事件冒泡来通知我们的列表容器(我想它是MainMxml的一个实例)关于需要删除行。我们应该为此创建一个事件类。

NB。您可以使用相同的事件类,但问题是您的ClearableTextInput组件和项呈示器具有不同的职责 并且ClearableTextInput可以在其他一些渲染器中再次使用。最好为应用程序的不同层创建不同的事件以实现低耦合:

package events {
    public class RemoveRowEvent extends Event {
        public static const REMOVE_CURRENT_ROW:String = "removeCurrentRow";
        public function RemoveRowEvent(type:String) {
            super(type, true);
        }

    }
}

现在你的渲染器:

<?xml version="1.0" encoding="utf-8"?>
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" 
                xmlns:s="library://ns.adobe.com/flex/spark" 
                xmlns:mx="library://ns.adobe.com/flex/mx" 
                autoDrawBackground="true" xmlns:components="components.*" width="100%">

    <s:layout> 
        <s:HorizontalLayout/> 
    </s:layout> 

    <fx:Script>
        <![CDATA[
            import mx.core.EdgeMetrics;
            import mx.core.UIComponent;

            import skins.ClearableTextInputSkin;

        ]]>
    </fx:Script>


    <components:ClearableTextInput id="clearTxt" text="{data.label}" skinClass="skins.ClearableTextInputSkin" performClear="dispatchEvent(new RemoveRowEvent(RemoveRowEvent.REMOVE_CURRENT_ROW))" />

</s:ItemRenderer>

最后在你的列表容器中(我想假设MainMxml):

…
addEventListener(RemoveRowEvent.REMOVE_CURRENT_ROW, onRowRemove);
…

private function onRowRemove(event:RemoveRowEvent):void {
    removeItem();
    event.stopImmediatePropagation();
}

我在浏览器中写了这个草稿,所以请自行修改导入等:)