I only thought I was done refactoring the Projects to use the MVVM pattern. Turns out that two of the three views in the level editor were not converted yet. The Map Select window will not be converted anytime soon either, but its very simple to begin with and not a big deal if it isn't. It cannot be converted at this time because the GMap control does not support MVVM. The other page that I needed to convert is the Edit Level Window, where all of the map editing will be done. It took quite a bit of doing, but I finally forced it into compliance. I am not happy with the results though, and I think some more refactoring is in order.
The biggest challenge that I ran into was getting the my ViewModel for the page, and the custom Map Control to play nicely together. The custom canvas control that I am using does not support any sort of bindings, so I was forced to write my own.
Here is what a dependency property looks like
public static readonly DependencyProperty CurrentPointCommandProperty =
DependencyProperty.Register(
"CurrentPointObject",
typeof(Point),
typeof(MapCanvas),
new PropertyMetadata(new PropertyChangedCallback(OnPropertyChanges))
);
Dependency properties are quite easy once you get the hang of it. The string in the example above, is the name of a public property. The first type is the type of the property being referenced, and the second type is the type of whatever object the property resides in. This also contains a Callback when the property changes
private static void OnPropertyChanges(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
(obj as MapCanvas).InvalidateVisual();
}
So anytime a property changes the Visual on the mapCanvas is overwritten.
Nothing much to it so far. My biggest concern is the number of DP's that I have to register just to do something simple.
Now, the second change I made here, was to use the
MVVM Light Toolkit instead of the custom implementation I created to handle the commands. This toolkit allowed me in conjuction with the Blend SDK to wire up commands to events that fire on the page rather than the control.
For example
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WPF4"
<i:Interaction.Triggers>
<i:EventTrigger EventName="KeyDown">
<cmd:EventToCommand Command="{Binding OnKeyDown}" PassEventArgsToCommand="True" />
</i:EventTrigger
</i:Interaction.Triggers>
This code allows me to bind to the KeyDown Event. It allows my viewmodel to recieve the eventArgs as well. Very useful.
My next step is probably going to involve some refactoring. I think that I can use the MVVM Light messages to help pass information from ViewModel to ViewModel, and also ViewModel to View. Doing so should cut down on the amount of code and Dependency Properties required. Even if most of them are refactored out, I learned a ton about using them and debugging them!