Кнопка удаления в ItemRenderer дает ошибку - PullRequest
0 голосов
/ 20 июня 2011

Я использую следующий .as-файл в качестве компонента для рендера элементов в списке.В основном каждый элемент отображается в TextInput, и каждый TextInput имеет кнопку удаления, как вы можете видеть из кода.При нажатии кнопки удаления я хочу удалить selectedItem .. поэтому я помещаю функцию 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 Ответ

1 голос
/ 20 июня 2011

Ответ может быть очень очень длинным:)

Начиная с вашего кода, проблема в строке:

mainMxml.removeItem();

Ваш mainMxml экземпляр - null, и поэтому у вас есть NPE (исключение нулевого указателя).

Но в целом код показывает, что вы в настоящее время не понимаете Flex, особенно привязку данных. И, конечно, есть проблемы с архитектурой приложения.

Сначала ваша строка:

[Bindable]
public var mainMxml:MainMxml;

ничего не делает.

Привязка данных - это просто способ прослушивания изменений переменной, помеченных метатегом [Bindable]. [Bindable] - это не инъекция зависимости, а полная противоположность этому.

Так что никто не установил значение вашего mainMxml поля. И, по правде говоря, это не правильный способ попытаться ввести туда ценность. Вместо этого вы должны использовать шаблон проектирования Observer и запуск события из вашего компонента:

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

        }
    }
}

Ok. Теперь наш рендер. Там мы должны использовать всплывающее окно события, чтобы сообщить нашему контейнеру списка (я полагаю, это экземпляр 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();
}

Я написал этот черновик в браузере, поэтому, пожалуйста, исправьте импорт и т. Д. Самостоятельно:)

...