Good stuff. Thanks.
I have already modified it to support some additional features...
cal:Message.Attach="[Event SomeEvent] = [Action MyHandler($convertargs)] : [Callback MyCallback]"
To use it, the view must implement the following interface...
/// Denotes a view that is capable of converting certain events into an object that the
/// ViewModel understands.
public interface ICanConvertEventArgs : IHaveActionMessageCallbacks
/// Creates a new object, based on <see cref="context.EventArgs"/>, that the bound method understands.
/// <param name="context">contains EventArgs and other information that may be helpful</param>
/// <returns>An object that will be passed as a parameter to the view model's bound method</returns>
object ConvertEventArgs(ActionExecutionContext context);
public delegate void ActionMessageCallback(ActionExecutionContext context, object arguments, object result);
/// Denotes a view that has one or more callback methods that can be bound to by <see cref="ActionMessage"/>
/// Callbacks are useful for inspecting the result and/or state of the parameters to determine if anything
/// special should be done with the <see cref="ActionExecutionContext.EventArgs"/>.
public interface IHaveActionMessageCallbacks
The marker interface IHaveActionMessageCallbacks was necessary because I could not figure out any other way to accurately identify the code-behind class when traversing the visual tree. The two interfaces should probably inherit a common marker interface
rather than one inheriting the other, because neither feature is really dependent on the other. As it turns out I'm not even using the callback feature, since they are only necessary if I don't want to wrap/encapsulate an event.