我正在创建一个应用程序,其中有两个mxml组件MainPanel.mxml和TextPanel.mxml,它们包含在名为index.mxml的父应用程序中。当我输入TextPanel.mxml中存在的文本框时,我希望能够将此数据绑定到TextPanel.mxml中存在的标签。我知道这可以通过以下方式完成:
<mx:Label text="{Application.application.textArea.text1.text}" />
但是,我想让我的组件更容易与系统交换,这会创建我不想要的依赖项。
以下是我提出的解决方案,虽然我觉得有更好的方法(为简洁起见省略了一些代码)。
index.mxml(父应用程序):
<mx:Script>
<![CDATA[
[Bindable]
private var _text:String;
private function handleTextChange(input:String):void {
_text = input;
}
]]>
</mx:Script>
<tp:TextPanel id="textArea"
textChange="handleTextChange(event.stringData)"/>
<cp:MainPanel id="mainArea" text = "{_text}" />
TextPanel.mxml:
<mx:Metadata>
[Event(name="textChange", type="events.CustomStringDataEvent")]
</mx:Metadata>
<mx:Script>
<![CDATA[
import events.CustomStringDataEvent;
private function textChangeHandler(event:Event):void {
var input:String = event.target.text;
dispatchEvent(new CustomStringDataEvent(input, 'textChange'));
}
]]>
</mx:Script>
<mx:TextInput id="text1" change="textChangeHandler(event)"/>
MainPanel.mxml
<mx:Script>
<![CDATA[
[Bindable]
public var text:String;
]]>
</mx:Script>
<mx:Label text="{text}" />
最后我的问题是,在两个兄弟组件之间创建松散耦合的最佳做法是什么?
答案 0 :(得分:2)
这是一种做法,当然。但是你也可以创建另一个类来保存由一个(或任何)组件写入的数据,然后为每个组件提供对该对象的引用;这可以通过少量代码和手动事件处理获得相同的效果。
例如,保存数据的类对象可能如下所示(请注意公共成员上的Bindable
属性:
package
{
public class MyBindableObject
{
[Bindable]
public var myStringProperty:String = "";
public function MyBindableObject()
{
//
}
}
}
...和你的主应用程序容器,它最初将实例化对象(并分发对其子组件的引用),如下所示:
<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" xmlns:local="*" initialize="this_initialize(event)">
<mx:Script>
<![CDATA[
[Bindable]
private var myObject:MyBindableObject;
private function this_initialize(event:Event):void
{
myObject = new MyBindableObject();
}
]]>
</mx:Script>
<mx:TextInput text="{myObject.myStringProperty}" />
<local:MyCustomComponent myObject="{myObject}" />
<local:MyOtherCustomComponent myObject="{myObject}" />
</mx:WindowedApplication>
...和MyCustomComponent(请注意Bindable
&amp; Inspectable
属性),在这种情况下恰好直接写入myObject.myStringProperty
:
<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
[Bindable]
[Inspectable]
public var myObject:MyBindableObject;
private function myEventHandler(event:Event):void
{
myObject.myStringProperty = txt.text;
}
]]>
</mx:Script>
<mx:TextInput id="txt" text="{myObject.myStringProperty}" keyUp="myEventHandler(event)" />
...和MyOtherCustomComponent,它接收前一个组件中所做的更改(并且偶然传播到容器应用程序):
<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
[Bindable]
[Inspectable]
public var myObject:MyBindableObject;
]]>
</mx:Script>
<mx:TextInput text="{myObject.myStringProperty}" />
</mx:Canvas>
同样,容器应用程序初始化对象实例,将其自己的子组件属性之一绑定到该对象的属性值(可选),并将对该对象的引用交给其子组件可能想要使用它的任何子组件。在这种情况下,第二个组件写入值,另外两个组件立即获得更改,因为MyBindableObject类上的myStringProperty标记为Bindable,并且每个组件都包含一个用于更改该属性的侦听器。
这个例子有点简单,因为它只是在某个对象上设置一个字符串值,从而将事件派发工作卸载到Flex框架,这只消除了几行代码 - 但这可能是一件好事因为实际上没有必要为简单的文本更改/属性更改事件设计自定义事件,因为Flex会为您处理大部分甚至全部工作。
然而,它仍取决于您希望自定义TextPanel的程度。如果你想将它开发成一个更复杂的组件,那么我可能建议将初始对象实例化移动到TextPanel本身,就像你通过定义和调度其他自定义事件,以及拥有主应用程序和兄弟组件一样。通过textPanel.addEventListener(或类似于MXML内联)或textPanel.myObject.addEventListener监听组件或可绑定对象上的事件通知,具体取决于哪些是合适的。
答案 1 :(得分:1)
你在这里所做的是mediator pattern的一种实现,这是一种完全可以接受的做事方式,在我看来,可能是你正在寻找的“最佳实践”,因为您正在使用的组件并不直接相互依赖 - 它们只是分派事件并让其他人处理“更高级别”的功能。
执行此操作的另一种方法是dependency injection,您可以在其中为组件提供相互引用,并让它们直接进行通信。这样你会使组件彼此依赖(或者可能不是彼此完全相同,但实现相同接口的任何东西),但你不必编写任何中介代码。在这里,与中介模式相反,我所指的“更高级别”功能实际上是组件本身而不是其他人(中介者)的责任。