CXMessage

From cxwiki

CXMessage is typically used for passing user-initiated event messages (such as button clicks) from the point in the user interface hierarchy that they were initiated up to the point at which they will be handled. That said, there is nothing user-interface-specific about the class and it may be reused for other purposes. Each message includes a name (identifying the event; eg. "click"), a source (identifying where the event originated) and may optionally include an event-specific data payload.
 
The CXMessageTarget baseclass is used to form a message-passing hierarchy. UIElement derives from CXMessageTarget appropriately, so the entire user interface hierarchy automatically provides a CXMessageTarget event hierarchy. Non-user-interface objects may also derive CXMessageTarget in order to participate in message passing.

CXMessage Passing

A CXMessage object is constructed (often on the stack) by the code which determines that the event has occurred. It is then passed to the virtual CXMessageTarget::Message() function on an appropriate CXMessageTarget (often "this"). If Message() is overriden, the messages are passed down the C++ class hierarchy until they reach the base CXMessageTarget::Message() at which point the message is passed to the parent CXMessageTarget and the process repeats. Messages may be handled by any overridden Message() function along the way. Handled messages may stop processing at that point, or may be allowed to propagate as normal, either before or after the handler code. In some cases, handler code may wish to absorb the message in question and re-emit a different message (actual modification of the original CXMessage object is not possible, although in rare cases the CXMessage object may include an immutable payload which in turn refers to a mutable object). Generally speaking, messages should be propagated by handlers unless there is a specific reason that the parent objects should never be aware of the message.

Control Flow

Message-passing occurs within the normal C++ control flow, and is not pushed off to a separate event queue or thread.
 
In a scenario where immediate message dispatch is not workable (such as when the message originates on the wrong thread, or where the current control flow should not be interrupted by the message handling), the CXMessagePost mechanism exists to provide delayed dispatch.

Result Code

A Message() override which handles a message will typically return a result code indicating the success or failure of the event handling. In many cases, this result will be ignored by the caller, but it may be used in some cases to determine whether a message was handled. If the root message handler is reached without the message being handled anywhere, the CXResultCode::NotImplemented result is returned. Some uses cases for this mechanism include:
  • Sending a new-version message, and in the even that the message was not handled, following up with an old-version message to allow legacy code to function correctly.
  • Sending a "close window?" message, and allowing the handlers to decide whether the window close may proceed, or whether it should be cancelled. If the message remains unhandled, or if the handler responds with a success code, the window close proceeds.

Message Payloads

CXMessage is a polymorphic class, and payloads are included into the message where necessary by creating a CXMessage-derived object rather than a base CXMessage. The derived object may add whatever fields or functionality is required for that specific event. Handlers which are aware of that event should cast the received message into the appropriate derived type to retrieve the payload.