在FLEX中调度自定义事件的问题

时间:2021-06-20 11:49:34

Let me start off by saying that I'm pretty new to flex and action script. Anyways, I'm trying to create a custom event to take a selected employee and populate a form. The event is being dispatched (the dispatchEvent(event) is returning true) but the breakpoints set inside of the handler are never being hit.

让我先说我对flex和动作脚本很新。无论如何,我正在尝试创建一个自定义事件来接受选定的员工并填充表单。正在调度该事件(dispatchEvent(event)返回true)但是在处理程序内部设置的断点永远不会被命中。

Here is some snippets of my code (Logically Arranged for better understanding):

以下是我的代码的一些片段(逻辑安排以便更好地理解):

Employee Form Custom Component

员工表单自定义组件

<mx:Metadata>
     [Event(name="selectEmployeeEvent", type="events.EmployeeEvent")]
<mx:Metadata>
<mx:Script>
   [Bindable]
   public var selectedEmployee:Employee;
</mx:Script>
...Form Fields

Application

<mx:DataGrid id="grdEmployees" width="160" height="268"
            itemClick="EmployeeClicked(event);">
<custom:EmployeeForm
     selectEmployeeEvent="SelectEmployeeEventHandler(event)"
     selectedEmployee="{selectedEmployee}" />

<mx:Script>
    [Bindable]
private var selectedEmployee:Employee;

private function EmployeeClicked(event:ListEvent):void
    {
     var employeeData:Employee;
     employeeData = event.itemRenderer.data as Employee;
     var employeeEventObject:EmployeeEvent = 
             new EmployeeEvent( "selectEmployeeEvent", employeeData);
     var test:Boolean = dispatchEvent(employeeEventObject);
         //test == true in debugger
}
    private function SelectEmployeeEventHandler(event:EmployeeEvent):void
    {
         selectedEmployee = event.Employee; //This event never fires
    }



</mx:Script>

2 个解决方案

#1


There are a few things conspiring to cause trouble here. :)

在这里有一些阴谋导致麻烦的事情。 :)

First, this declaration in your custom component:

首先,您的自定义组件中的此声明:

<mx:Metadata>
     [Event(name="selectEmployeeEvent", type="events.EmployeeEvent")]
<mx:Metadata>

... announces to the compiler that your custom component dispatches this particular event, but you're actually dispatching it with your containing document, rather than your custom component -- so your event listener never gets called, because there's nothing set up to call it.

...向编译器宣布您的自定义组件调度此特定事件,但您实际上是使用包含文档而不是自定义组件调度它 - 因此您的事件侦听器永远不会被调用,因为没有任何设置可以调用它。

Another thing is that, in list-item-selection situations like this one, the more typical behavior is to extract the object from the selectedItem property of the currentTarget of the ListEvent (i.e., your grid -- and currentTarget rather than target, because of the way event bubbling works). In your case, the selectedItem property of the grid should contain an Employee object (assuming your grid's dataProvider is an ArrayCollection of Employee objects), so you'd reference it directly this way:

另一件事是,在像这样的列表项选择情况下,更典型的行为是从ListEvent的currentTarget的selectedItem属性中提取对象(即,你的网格 - 和currentTarget而不是target,因为事件冒泡的方式)。在您的情况下,网格的selectedItem属性应包含一个Employee对象(假设您的网格的dataProvider是Employee对象的ArrayCollection),因此您可以通过以下方式直接引用它:

private function employeeClicked(event:ListEvent):void
{
   var employee:Employee = event.currentTarget.selectedItem as Employee;
   dispatchEvent(new EmployeeEvent("selectEmployeeEvent"), employee);
}

Using the itemRenderer as a source of data is sort of notoriously unreliable, since item renderers are visual elements that get reused by the framework in ways you can't always predict. It's much safer, instead, to pull the item from the event directly as I've demonstrated above -- in which case you wouldn't need an "employeeData" object at all, since you'd already have the Employee object.

使用itemRenderer作为数据源是一种众所周知的不可靠,因为项呈示器是可视元素,它们以您无法总是预测的方式被框架重用。相反,如上所述,直接从事件中提取项目会更安全 - 在这种情况下,您根本不需要“employeeData”对象,因为您已经拥有了Employee对象。

Perhaps, though, it might be better to suggest an approach that's more in line with the way the framework operates -- one in which no event dispatching is necessary because of the data-binding features you get out-of-the-box with the framework. For example, in your containing document:

但是,或许,建议一种更符合框架运行方式的方法可能会更好 - 一种不需要事件调度的方法,因为数据绑定功能可以使您获得开箱即用的功能。框架。例如,在您的包含文档中:

<mx:Script>
    <![CDATA[

        import mx.events.ListEvent;

        [Bindable]
        private var selectedEmployee:Employee;

        private function dgEmployees_itemClick(event:ListEvent):void
        {
            selectedEmployee = event.currentTarget.selectedItem as Employee;
        }

    ]]>
</mx:Script>

<mx:DataGrid id="dgEmployees" dataProvider="{someArrayCollectionOfEmployees}" itemClick="dgEmployees_itemClick(event)" />

<custom:EmployeeForm selectedEmployee="{selectedEmployee}" />

... you'd define a selectedEmployee member, marked as Bindable, which you set in the DataGrid's itemClick handler. That way, the binding expression you've specified on the EmployeeForm will make sure the form always has a reference to the selected employee. Then, in the form itself:

...您将定义一个标记为Bindable的selectedEmployee成员,您可以在DataGrid的itemClick处理程序中设置该成员。这样,您在EmployeeForm上指定的绑定表达式将确保表单始终具有对所选员工的引用。然后,在表单本身:

<mx:Script>
    <![CDATA[

        [Bindable]
        [Inspectable]
        public var selectedEmployee:Employee;

    ]]>
</mx:Script>

<mx:Form>
    <mx:FormItem label="Name">
        <mx:TextInput text="{selectedEmployee.name}" />
    </mx:FormItem>
</mx:Form>

... you simply accept the selected employee (which is marked bindable again, to ensure the form fields always have the most recent information about that selected employee).

...您只需接受所选员工(再次标记为可绑定,以确保表单字段始终包含有关所选员工的最新信息)。

Does this make sense? I might be oversimplifying given that I've no familiarity with the requirements of your application, but it's such a common scenario that I figured I'd throw an alternative out there just for illustration, to give you a better understanding of the conventional way of handling it.

这有意义吗?鉴于我对您的应用程序的要求并不熟悉,我可能会过于简单化,但是我认为我会在那里抛出一个替代方案,仅仅是为了说明,让您更好地理解传统的方法。处理它。

If for some reason you do need to dispatch a custom event, though, in addition to simply setting the selected item -- e.g., if there are other components listening for that event -- then the dispatchEvent call you've specified should be fine, so long as you understand it's the containing document that's dispatching the event, so anyone wishing to be notified of it would need to attach a specific listener to that document:

如果由于某种原因你确实需要调度自定义事件,除了简单地设置所选项目 - 例如,如果有其他组件正在侦听该事件 - 那么你指定的dispatchEvent调用应该没问题,只要您了解它是调度事件的包含文档,那么任何希望得到通知的人都需要将特定的侦听器附加到该文档:

yourContainingDoc.addEventListener("selectEmployeeEvent", yourOtherComponentsSelectionHandler);

Hope it helps -- feel free to post comments and I'll keep an eye out.

希望它有所帮助 - 随意发表评论,我会留意。

#2


You're dispatching the event from the class in the lower code sample (DataGrid, I guess), but the event is defined in the EmployeeForm class, and the event handler is likewise attached to the EmployeeForm instance. To the best of my knowledge, events propagate up in the hierarchy, not down, so when you fire the event from the form's parent, it will never trigger handlers in the form itself. Either fire the event from the form or attach the event handler to the parent component.

您将从较低代码示例(DataGrid,我猜)中的类调度该事件,但该事件在EmployeeForm类中定义,并且事件处理程序同样附加到EmployeeForm实例。据我所知,事件在层次结构中向上传播,而不是向下传播,因此当您从表单的父级触发事件时,它将永远不会触发表单本身的处理程序。从表单触发事件或将事件处理程序附加到父组件。

#1


There are a few things conspiring to cause trouble here. :)

在这里有一些阴谋导致麻烦的事情。 :)

First, this declaration in your custom component:

首先,您的自定义组件中的此声明:

<mx:Metadata>
     [Event(name="selectEmployeeEvent", type="events.EmployeeEvent")]
<mx:Metadata>

... announces to the compiler that your custom component dispatches this particular event, but you're actually dispatching it with your containing document, rather than your custom component -- so your event listener never gets called, because there's nothing set up to call it.

...向编译器宣布您的自定义组件调度此特定事件,但您实际上是使用包含文档而不是自定义组件调度它 - 因此您的事件侦听器永远不会被调用,因为没有任何设置可以调用它。

Another thing is that, in list-item-selection situations like this one, the more typical behavior is to extract the object from the selectedItem property of the currentTarget of the ListEvent (i.e., your grid -- and currentTarget rather than target, because of the way event bubbling works). In your case, the selectedItem property of the grid should contain an Employee object (assuming your grid's dataProvider is an ArrayCollection of Employee objects), so you'd reference it directly this way:

另一件事是,在像这样的列表项选择情况下,更典型的行为是从ListEvent的currentTarget的selectedItem属性中提取对象(即,你的网格 - 和currentTarget而不是target,因为事件冒泡的方式)。在您的情况下,网格的selectedItem属性应包含一个Employee对象(假设您的网格的dataProvider是Employee对象的ArrayCollection),因此您可以通过以下方式直接引用它:

private function employeeClicked(event:ListEvent):void
{
   var employee:Employee = event.currentTarget.selectedItem as Employee;
   dispatchEvent(new EmployeeEvent("selectEmployeeEvent"), employee);
}

Using the itemRenderer as a source of data is sort of notoriously unreliable, since item renderers are visual elements that get reused by the framework in ways you can't always predict. It's much safer, instead, to pull the item from the event directly as I've demonstrated above -- in which case you wouldn't need an "employeeData" object at all, since you'd already have the Employee object.

使用itemRenderer作为数据源是一种众所周知的不可靠,因为项呈示器是可视元素,它们以您无法总是预测的方式被框架重用。相反,如上所述,直接从事件中提取项目会更安全 - 在这种情况下,您根本不需要“employeeData”对象,因为您已经拥有了Employee对象。

Perhaps, though, it might be better to suggest an approach that's more in line with the way the framework operates -- one in which no event dispatching is necessary because of the data-binding features you get out-of-the-box with the framework. For example, in your containing document:

但是,或许,建议一种更符合框架运行方式的方法可能会更好 - 一种不需要事件调度的方法,因为数据绑定功能可以使您获得开箱即用的功能。框架。例如,在您的包含文档中:

<mx:Script>
    <![CDATA[

        import mx.events.ListEvent;

        [Bindable]
        private var selectedEmployee:Employee;

        private function dgEmployees_itemClick(event:ListEvent):void
        {
            selectedEmployee = event.currentTarget.selectedItem as Employee;
        }

    ]]>
</mx:Script>

<mx:DataGrid id="dgEmployees" dataProvider="{someArrayCollectionOfEmployees}" itemClick="dgEmployees_itemClick(event)" />

<custom:EmployeeForm selectedEmployee="{selectedEmployee}" />

... you'd define a selectedEmployee member, marked as Bindable, which you set in the DataGrid's itemClick handler. That way, the binding expression you've specified on the EmployeeForm will make sure the form always has a reference to the selected employee. Then, in the form itself:

...您将定义一个标记为Bindable的selectedEmployee成员,您可以在DataGrid的itemClick处理程序中设置该成员。这样,您在EmployeeForm上指定的绑定表达式将确保表单始终具有对所选员工的引用。然后,在表单本身:

<mx:Script>
    <![CDATA[

        [Bindable]
        [Inspectable]
        public var selectedEmployee:Employee;

    ]]>
</mx:Script>

<mx:Form>
    <mx:FormItem label="Name">
        <mx:TextInput text="{selectedEmployee.name}" />
    </mx:FormItem>
</mx:Form>

... you simply accept the selected employee (which is marked bindable again, to ensure the form fields always have the most recent information about that selected employee).

...您只需接受所选员工(再次标记为可绑定,以确保表单字段始终包含有关所选员工的最新信息)。

Does this make sense? I might be oversimplifying given that I've no familiarity with the requirements of your application, but it's such a common scenario that I figured I'd throw an alternative out there just for illustration, to give you a better understanding of the conventional way of handling it.

这有意义吗?鉴于我对您的应用程序的要求并不熟悉,我可能会过于简单化,但是我认为我会在那里抛出一个替代方案,仅仅是为了说明,让您更好地理解传统的方法。处理它。

If for some reason you do need to dispatch a custom event, though, in addition to simply setting the selected item -- e.g., if there are other components listening for that event -- then the dispatchEvent call you've specified should be fine, so long as you understand it's the containing document that's dispatching the event, so anyone wishing to be notified of it would need to attach a specific listener to that document:

如果由于某种原因你确实需要调度自定义事件,除了简单地设置所选项目 - 例如,如果有其他组件正在侦听该事件 - 那么你指定的dispatchEvent调用应该没问题,只要您了解它是调度事件的包含文档,那么任何希望得到通知的人都需要将特定的侦听器附加到该文档:

yourContainingDoc.addEventListener("selectEmployeeEvent", yourOtherComponentsSelectionHandler);

Hope it helps -- feel free to post comments and I'll keep an eye out.

希望它有所帮助 - 随意发表评论,我会留意。

#2


You're dispatching the event from the class in the lower code sample (DataGrid, I guess), but the event is defined in the EmployeeForm class, and the event handler is likewise attached to the EmployeeForm instance. To the best of my knowledge, events propagate up in the hierarchy, not down, so when you fire the event from the form's parent, it will never trigger handlers in the form itself. Either fire the event from the form or attach the event handler to the parent component.

您将从较低代码示例(DataGrid,我猜)中的类调度该事件,但该事件在EmployeeForm类中定义,并且事件处理程序同样附加到EmployeeForm实例。据我所知,事件在层次结构中向上传播,而不是向下传播,因此当您从表单的父级触发事件时,它将永远不会触发表单本身的处理程序。从表单触发事件或将事件处理程序附加到父组件。