In my last post, I introduced a solution that I put together for invoking UI code in response to ViewModel changes or events. Please read that post for a full explanation. After using the code a bit, I found the need to easily specify multiple methods to be invoked in response to a single ViewModel change. I extended the framework adding a couple new attached collection properties that allow me to specify multiple method calls, as well as a little clean-up to simplify the framework.
Here is a summary of my changes:
Losing the MethodCaller.OnEventMethodCall property
I realized that since the OnEventMethodCall object derives from MethodCall, there’s no reason to have a separate attached property for specifying an OnEventMethodCall. So I dropped the MethodCaller.OnEventMethodCall attached property. The MethodCaller.MethodCall property should be used instead:
<mc:MethodCaller.MethodCall>
<mc:OnEventMethodCall EventName="Click" MethodName="SelectPerson">
<mc:MethodCall.Arguments>
<mc:MethodArgument Value="{Binding}" />
</mc:MethodCall.Arguments>
</mc:OnEventMethodCall>
</mc:MethodCaller.MethodCall>
This makes it cleaner, and also I can create further MethodCall subclasses down the road if needed and use the same attached property to set them up.
Multiple MethodCalls in a trigger
I added a new attached property called MethodCaller.SetMethodCalls that takes in a MethodCallCollection object. This allows me to specify any number of MethodCall objects to be invoked when the trigger fires:
<Setter TargetName="uxRow" Property="mc:MethodCaller.SetMethodCalls">
<Setter.Value>
<mc:MethodCallCollection>
<mc:MethodCall MethodName="Focus" Target="{Binding ElementName=uxText}" />
<mc:MethodCall MethodName="BringIntoView" />
</mc:MethodCallCollection>
</Setter.Value>
</Setter>
Additionally, this MethodCaller.SetMethodCalls attached property would be used to specify MethodCall‘s (or OnEventMethodCall‘s) via a <Style>. Basically, anywhere you use a <Setter> to set the property. You’ll notice in the snippet above, that we’re passing in a new <MethodCallCollection> object. The SetMethodCalls property has no default value, so when setting it you must pass in a new MethodCallCollection.
Wiring multiple events on the same object
The last change is almost identical to the one I just mentioned. I added another attached property called MethodCaller.MethodCalls that exposes a MethodCallCollection object. The difference between this property and the SetMethodCalls property described above is that this collection is already initialized and instantiated, so you can just add to it without creating a new MethodCallCollection object:
<mc:MethodCaller.MethodCalls>
<mc:OnEventMethodCall EventName="Click" MethodName="SelectPerson">
<mc:MethodCall.Arguments>
<mc:MethodArgument Value="{Binding}" />
</mc:MethodCall.Arguments>
</mc:OnEventMethodCall>
<mc:OnEventMethodCall EventName="MouseLeftButtonUp" MethodName="Focus" />
</mc:MethodCaller.MethodCalls>
(Note: creating a read-only attached property of type collection can be tricky because you need to initialize the collection, but unless you do some special setup, the Getter is not called upon first access like you might expect. And setting a default value via the Attached Property’s Default Value mechanism doesn’t work either, because the value you specified is a shared value and not unique to the instance of the dependency property. See Bill Kempf’s post and John Gossman’s post for more information and explanation of the why’s and how’s.)
Summary
In working with the MethodCaller framework, I found these changes to be useful, so I wanted to post them. The latest code can be downloaded here. I may make another post in the future walking through some of the actual code behind this solution in case anyone is interested.
Thanks for reading!
—Benjamin