我使用以下.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>
非常感谢您的帮助。
非常感谢。
答案 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();
}
我在浏览器中写了这个草稿,所以请自行修改导入等:)