coerce parameters on ActionMessage?

Feb 17, 2011 at 11:25 PM

I am ending up with more and more ViewModels making use control-specific events, and it just does not sit well with me. One of the common MVVM solutions is to create an attached behavior to handle events and make use of commands that can pass along any event properties. I would like to maybe add a little functionality to ActionMessage that handles most of the boiler plate for this.

My thought is that the View (somehow, maybe code-behind) converts between an event or other parameter type and the parameter type expected by the attached method. Maybe a CoerceValueConverter : IValueConverter, instantiated for each attached message, could hold the array of parameters, so that after the action is invoked, the View (somehow, maybe code-behind) has the option to finish handling of the event by inspecting the parameters and modifying any EventArg properties accordingly.

Any thoughts? Will it work? Worth the effort?

Oh! I just saw that MessageBinder has a method CoerceValue. It's simply value conversion, but it shouldn't be too difficult to make it a little more pluggable.

Feb 18, 2011 at 1:38 AM

I'm not sure I understand your scenario. Can you give me a concrete example?

Feb 18, 2011 at 6:00 AM

cal:Message.Attach="[Event SomeThirdPartyEvent] = [Action DoAction($eventargs)]"
cal:Message.CoerceParameters="[Event SomeThirdPartyEvent] = [Convert_SomeThirdPartyEvent]"
cal:Message.ModifyParameters="[Event SomeThirdPartyEvent] = [Modify_SomeThirdPartyEvent]"

I don't want the view model to be coupled to a third-party library, so it would be nice if there were some way to wrap or encapsulate or intercept the $eventargs parameter so that the parameter that DoAction(MyEventInfo info) expects is view-agnostic.

I know I could ceate an attched behavior to register a handler with SomeThirdPartyEvent that will create a MyEventInfo and execute DoAction() with it. I just hope it would be possible to eliminate the boiler plate code by adding a behavior to cal:Message that can delegate to the view the creation of a MyEventInfo.

Convert_SomeThirdPartyEvent is code-behind that takes a SomeThirdPartyEvent and returns a MyEventInfo.

Modify_SomeThirdPartyEvent is code-behind that is executed after DoAction() that can follow up on any changes to MyEventInfo, to support situations where a propery on SomeThirdPartyEvent needs to be updated.

Feb 18, 2011 at 2:10 PM
Edited Feb 18, 2011 at 2:20 PM

Ok. This is easy to plugin. Just use the MessageBinder to add a new special parameter value. You would do something like this:

MessageBinder.SpecialValues.Add("$convertargs", context => ConvertToSpecialType(context.EventArgs));

Make sure to define your special value in lower case.

Feb 18, 2011 at 5:15 PM

Cool. How would you recommend I implement a hook to execute after the action is invoked so that view code-behind has an opportunity to inspect the parameter? If SomeThirdPartyEvent has, say, a Cancel property, I might want to set it according to the state of the parameters.

Feb 18, 2011 at 5:19 PM

Have a look at ActionMessage.InvokeAction This is a replacable func, so you can use the implementation I have and augment it with the functionality you need.

Feb 23, 2011 at 10:46 PM

Okay, I am making good progress on this, but I am stuck on something. I want to add callback functionality to ActionMessage by adding a CallbackNameProperty and a method TryFindCallbackMethod() that will search the code behind class for the method. The purpose of the callback is primarily to be able to inspect the result of a message invocation and/or the state of any parameters and modify any properties in ActionExecutionContext.EventArgs accordingly.

The problem is how to properly identify the code behind class. The only thing I can think of is to put a marker interface IHaveActionMessageCallbacks on the view class and loop through an element's parents until I find one that implements this. I'll go ahead and try it, but please let me know if you can think of a better approach. Thanks.

Feb 24, 2011 at 1:21 AM

You can *probably* just walk up the tree until you find a UserControl or Window....*probably*...