I've already built something that works well for me. Essentially, it
consists of events, event listeners, and event dispatchers. Component
event dispatchers are tied in one-to-one correspondence with components
through a component attribute. The component dispatcher does bubbling.
There's a factory for turning Java methods into event listeners, because
nobody likes defining anonymous classes. That's pretty much it.
The event bus you describe with routing rules and whatnot sounds more
complicated than what I need. Thanks for the tip, though. What's your
name?
Michael
On Mon, 26 Jul 2010, aappddeevv wrote:
Message bus for inter-object communication versus parent-tree messaging
conceptually is the same, however, parent-tree messaging can be simplified
somewhat and built to be more optimized then a general-purpose message-bus
approach. There is general message bus, like spring integration, message
brokering like EventBus/e4 and then parent-tree bubbling like wpf. In terms
of routing strategy, parent-tree is pretty straight forward. Routing based
on strings/ids/header like EventBus can be managed well and adopting general
purpose mechanisms like spring integration is much more challenging.
You can implement a bubbling router using attached properties, however, for
robustness, something more like WPF's style is a bit better and I switched
to AOP for a couple of reasons when I implemented events. You can create the
synthetic events by attaching listeners to all of the listeners in a
component (and other objects) and translate that into event message types.
One balance between the listener style in pivot and data-driven events is
that you have to flatten the listeners into event types...not hard at all.
When I built pivot-aspects, I flattened all the listeners into two common
APIs for PCL and events in order to go data driven and do event processing.
Doing this was the only way to be uniform throughout although there are
probably 2-3 ways to do it. Pivot already bubbles some events such as keys
and mousing which covers a lot of what people are usually after.
I found that MessageBus does not solve enough of a problem to warrant its
use for many scenarios. It works fine for simple messaging though which is
what it was designed to do. EventBus has richer support for inter-object
communication and works fine and is easy to start using. I did not find
bubbling of a general event to be critical yet but flattening was important
for triggering.
If you are looking for bubbling, I suggest you look at AOP to implement it
cleanly although build complexity increases. It would also allow to
implement handlers consistently without API requirements. I implemented
handlers for Execute/CanExecute and a pluggable handler framework so you can
have your own handler protocol but tastes vary. Because mouse/keys are
already handled okay, the need for robust bubbling was decreased as
supporting triggers required less infrastructure. In some cases where a
bubbling event could be helpful, walking the parent-child tree is a
quick-easy alternative to full event support.
Here's some starting code for "tree events"
/**
* A class for tree events to inherit from. Essentially, TreeEvent is the
"type" of event and this class is an instance of a TreeEvent.
Subclasses should extend for their event types.
*
*/
public class TreeEventInstance {
public TreeEvent event;
/**
* The logical element that raised the event.
*/
public Component source;
/**
* The visual that raised the event.
*/
private Component originalSource;
/**
* The last sender of this event.
*/
private Object sender;
private boolean handled = false;
private Map<String, Object> attributes = new HashMap<String, Object>();
....
/**
* An event occurring in the tree. There are no
* interface or method requirements on the handlers for
* receiving these events. A tree event is
* really a message that has a potentially
* predefined notion of the direction to route. Instead of the class
* of the object indicating a payload type, essentially the id
* indicates a payload type in the message.
*
*/
public class TreeEvent {
/**
* The routing strategy. This helps indicate
* how it should be routed when the context of routing up or down
* is well-defined.
*
*/
public enum Routing {
/**
* Event goes up the tree.
*/
UP,
/**
* Event goes down the tree.
*/
DOWN,
/**
* Event is only raised on the element and does not route up or down.
*/
DIRECT
};
public String id;
public Class<?> ownerType;
public Routing routing;
...
-----Original Message-----
From: Michael Allman [mailto:[email protected]]
Sent: Monday, July 26, 2010 12:29 AM
To: [email protected]
Subject: Re: Backwards compatibility for WTKXSerializer
On Mon, 19 Jul 2010, Greg Brown wrote:
What other aspects of MXML would you like to see added to BXML?
Simple support for listening for custom bubbling events.
As I mentioned in a previous email, I think a pub/sub API is probably
better suited to the use case you describe.
I guess you're referring to MessageBus in trunk. If not, let me know.
Anyway, I think using MessageBus for event bubbling is---to use an old
cliche---like hammering a square peg into a round hole. For one thing, it
uses classes for event/message keys. I want to select on a message
name---a string. For another, MessageBus is global. A subscriber does
not know the source of the message without examining the message. I would
like to be able to subscribe for messages from an event dispatcher of my
choosing. Thus, I can have multiple event dispatchers dispatch the same
type of event and take a different action depending on which event
dispatcher dispatched the event. Finally, there's bubbling itself.
MessageBus does not provide support for bubbling, probably because it
doesn't know anything about the component hierarchy. I would like to be
able to "consume" events in such a way that ancestor listeners do not
receive them.
Also, being able to bind to arbitrary properties on suitably annotated
objects would be very helpful
This is already supported. The BXML annotation supports an "id" property
you can use to bind to any named object in the BXML file. It just
defaults to the name of the member variable.
I think we're referring to two different kinds of binding. I'm referring
to the event-driven kind. Are you?
Cheers,
Michael