I was thinking about an aspect of the new MVVM support that Expression Blend 4 has and how ( I think – someone can tell me if I’m wrong ) it all starts with a seemingly small change in data-binding in Silverlight.
If I take a ViewModel like this into Expression Blend 4;
using System; using System.ComponentModel; using System.Windows; using System.Windows.Input; using Microsoft.Expression.Interactivity.Core; namespace MvvmApplication2 { public class MainViewModel { public ICommand MessageBoxCommand { get { if (this.messageBoxCommand == null) { this.messageBoxCommand = new ActionCommand(parameter => { MessageBox.Show(string.Format("Parameter was {0}", parameter), null, MessageBoxButton.OK); }); } return(this.messageBoxCommand); } } ICommand messageBoxCommand; } }
and we set the ViewModel as the DataContext for a view then I can use the Data window in Blend in order to create “sample data” around it;
which then gives me a view such as;
and it’s cool because I can then create some piece of UI like this below where I have a Shape and a TextBox ( it’s just for example purposes here );
and I can then drag my MessageBoxCommand from my Data window in Blend over to that Shape and Blend will automatically “know” that what I want to do is invoke that command when something happens on that shape;
and what it does is generate an InvokeCommandAction and ties that to a Trigger on that Shape and the Trigger by default will sync up to the MouseLeftButtonDown event on the shape but it could equally be any other event and it certainly doesn’t have to have anything to do with a Click handler because ( AFAIK ) the Shape doesn’t even have one.
This allows me to be nice and declarative in my View and yet still bind to functionality on my ViewModel like my MessageBoxCommand. As an aside, if I didn’t have an ICommand property on my ViewModel but, instead, had a plain old method then Blend would do the right thing because it also has a CallMethodAction which can invoke a method on the DataContext ( in my case, the ViewModel ).
And so Blend preserves that View<->ViewModel separation for me using the triggers/actions/behaviors that began in Expression Blend 3.
My MessageBoxCommand took a parameter though and Blend provides for that too. I can go and grab that parameter in the properties window;
and bind it over to the Text property on my TextBox just by dragging and dropping ( note – I’m not saying that you would actually do this but it works for this example of getting a command parameter through to my command ).
Now, that’s kind of interesting because what Blend then generates is this lump of XAML;
<ed:Callout> <i:Interaction.Triggers> <i:EventTrigger EventName="MouseLeftButtonDown"> <i:InvokeCommandAction Command="{Binding MessageBoxCommand}" CommandParameter="{Binding Text, ElementName=textBox}"/> </i:EventTrigger> </i:Interaction.Triggers> </ed:Callout>
where you’ll notice that the InvokeCommandAction has its properties Command and CommandParameter databound to the respective properties on the ViewModel and the TextBox.
Now, in Silverlight 3 I don’t think this would have been possible because InvokeCommandAction derives from DependencyObject and, in Silverlight 3, you can’t have a target of a data-binding which is a DependencyObject – you have to derive from FrameworkElement and that wouldn’t really be right for InvokeCommandAction.
However…in Silverlight 4 you can have objects which are the target of bindings as long as they derive from DependencyObject and so ( for me ) what seems a little tiny change where the base class for the target of bindings moves from FrameworkElement to DependencyObject is what allows a designer to sit in Blend and nicely drag/drop my ICommand to the View and have Blend do the right thing.
Neat.
If you want to see more on this kind of thing in Blend 4 then I can strongly recommend this session from MIX the other week – it certainly got me thinking/playing with this stuff.