MTS Poland Presentation and sample

As promised, here are the slides and samples for my presentation in Poland on MVVM and Friends.

DOWNLOAD FROM HERE

If you need any help or have any questions feel free to send me an email at marlongrech AT gmail DOT Com (please not I wrote the email in such a way for spam readers)

Advertisements

How to set WPF ScrollViewer VerticalOffset and Horizontal offset

Today I needed to bind to the ScrolViewer VerticalOffset and Horizontal offset to do an animation for them. Yet unfortunately you cannot do this. In order to set these properties you need to use the ScrollToVerticalOffset or ScrollToHorizontalOffset methods :S This is not very good because it means you cannot do DataBinding or animate these properties….

Well as usual I resorted to  Attached Behaviour. Basically I created 2 attached properties one for HorizontalOffset and one for VerticalOffset. These properties just call the methods ScrollToVerticalOffset or ScrollToHorizontalOffset inside the property changed handlers… yep it’s as simple as that… Here is the attached behaviour class

   1: public class ScrollViewerUtilities

   2: {

   3:     #region HorizontalOffset

   4:  

   5:     /// <summary>

   6:     /// HorizontalOffset Attached Dependency Property

   7:     /// </summary>

   8:     public static readonly DependencyProperty HorizontalOffsetProperty =

   9:         DependencyProperty.RegisterAttached("HorizontalOffset", typeof(double), typeof(ScrollViewerUtilities),

  10:             new FrameworkPropertyMetadata((double)0.0,

  11:                 new PropertyChangedCallback(OnHorizontalOffsetChanged)));

  12:  

  13:     /// <summary>

  14:     /// Gets the HorizontalOffset property.  This dependency property 

  15:     /// indicates ....

  16:     /// </summary>

  17:     public static double GetHorizontalOffset(DependencyObject d)

  18:     {

  19:         return (double)d.GetValue(HorizontalOffsetProperty);

  20:     }

  21:  

  22:     /// <summary>

  23:     /// Sets the HorizontalOffset property.  This dependency property 

  24:     /// indicates ....

  25:     /// </summary>

  26:     public static void SetHorizontalOffset(DependencyObject d, double value)

  27:     {

  28:         d.SetValue(HorizontalOffsetProperty, value);

  29:     }

  30:  

  31:     /// <summary>

  32:     /// Handles changes to the HorizontalOffset property.

  33:     /// </summary>

  34:     private static void OnHorizontalOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)

  35:     {

  36:         var viewer = (ScrollViewer)d;

  37:         viewer.ScrollToHorizontalOffset((double)e.NewValue);

  38:     }

  39:  

  40:     #endregion

  41:  

  42:     #region VerticalOffset

  43:  

  44:     /// <summary>

  45:     /// VerticalOffset Attached Dependency Property

  46:     /// </summary>

  47:     public static readonly DependencyProperty VerticalOffsetProperty =

  48:         DependencyProperty.RegisterAttached("VerticalOffset", typeof(double), typeof(ScrollViewerUtilities),

  49:             new FrameworkPropertyMetadata((double)0.0,

  50:                 new PropertyChangedCallback(OnVerticalOffsetChanged)));

  51:  

  52:     /// <summary>

  53:     /// Gets the VerticalOffset property.  This dependency property 

  54:     /// indicates ....

  55:     /// </summary>

  56:     public static double GetVerticalOffset(DependencyObject d)

  57:     {

  58:         return (double)d.GetValue(VerticalOffsetProperty);

  59:     }

  60:  

  61:     /// <summary>

  62:     /// Sets the VerticalOffset property.  This dependency property 

  63:     /// indicates ....

  64:     /// </summary>

  65:     public static void SetVerticalOffset(DependencyObject d, double value)

  66:     {

  67:         d.SetValue(VerticalOffsetProperty, value);

  68:     }

  69:  

  70:     /// <summary>

  71:     /// Handles changes to the VerticalOffset property.

  72:     /// </summary>

  73:     private static void OnVerticalOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)

  74:     {

  75:         var viewer = (ScrollViewer)d;

  76:         viewer.ScrollToVerticalOffset((double)e.NewValue);

  77:     }

  78:  

  79:     #endregion

  80:  

  81: }

and here is XAMl of how I use this

   1: <Grid>

   2:     <Grid.RowDefinitions>

   3:         <RowDefinition />

   4:         <RowDefinition Height="100"/>

   5:     </Grid.RowDefinitions>

   6:     <ScrollViewer x:Name="scrollViewer" HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible"  >

   7:         <Border Width="9000" Height="9000"/> 

   8:     </ScrollViewer>

   9:     

  10:     <StackPanel Grid.Row="1">

  11:         <WrapPanel>

  12:             <TextBlock Text="Slider for horizontal: Value:" Margin="0,0,10,0"/>    

  13:             <TextBlock Text="{Binding ElementName=scrollViewer, Path=HorizontalOffset}"/>

  14:         </WrapPanel>

  15:         <Slider Value="{Binding ElementName=scrollViewer, Path=(local:ScrollViewerUtilities.HorizontalOffset)}" 

  16:                 Minimum="0" Maximum="9000"/>

  17:         <WrapPanel>

  18:             <TextBlock Text="Slider for vertical: Value:" Margin="0,0,10,0"/>

  19:             <TextBlock Text="{Binding ElementName=scrollViewer, Path=VerticalOffset}"/>

  20:         </WrapPanel>

  21:         <Slider Value="{Binding ElementName=scrollViewer, Path=(local:ScrollViewerUtilities.VerticalOffset)}" 

  22:                 Minimum="0" Maximum="9000"/>

  23:         

  24:         <WrapPanel>

  25:             <TextBlock Text="Animate scroll" Margin="0,0,10,0"/>

  26:             <Button Content="Do it">

  27:                 <Button.Triggers>

  28:                     <EventTrigger RoutedEvent="Button.Click">

  29:                         <BeginStoryboard>

  30:                             <Storyboard>

  31:                                 <DoubleAnimation Storyboard.TargetName="scrollViewer" 

  32:                                          Storyboard.TargetProperty="(local:ScrollViewerUtilities.VerticalOffset)"

  33:                                          Duration="0:0:1" DecelerationRatio="1.0" To="8000"/>

  34:                             </Storyboard>

  35:                         </BeginStoryboard>

  36:                     </EventTrigger>

  37:                 </Button.Triggers>

  38:             </Button>

  39:         </WrapPanel>

  40:     </StackPanel>

  41: </Grid>

Download the sample app I built for this…

Article revisited: MVVM + M (implementing a Fly Weight TreeView)

Ages ago I wrote an article to introduce an idea that I had for the Mediator pattern to work with MVVM (at that time MVVM was still in the being of its age so I didn’t even call it View Model I called it Controller).

Today I was preparing for a Demo that I will be doing in Poland and I thought to revisit this article and refactor it with the new methods that I discovered over the last year.

What’s new in the new and exciting in the new version.

>> Well for starters I am using a new and improved version of the Mediator. The new version of the Mediator API is much more user friendly. It support Generics and it also eliminates the need to have interfaces implemented for you ViewModel. Instead of implementing an interface and have a switch for the message type now you simple register a message to an Action delegate. The Action delegate can be of a generic type so that you don’t even have to cast the argument. You can read more on this over here.

>> This version also uses Service Locator and the concept of ViewModel Loaders that I introduced in this article.

>> It also uses attached behaviours for the TreeView instead of a ViewModel registering to routed events of the treeview through the EventManager. This is much better! Event Manager registration of event inside a ViewModel can be very dangerous and also makes the ViewModel dirty with references to UI elements. Yet at that time it was an approach that I thought was best, as I said those days were just when View Model concept was emerging…

It’s amazing what I have learnt in the last year and how much MVVM evolved!

Download the source code and have a look for yourself…. Compare the 2 versions and see how much better we WPF developers can today use MVVM 🙂

Animating width and height when they are Double.NaN

A common problem in WPF when doing animation to width and height is that you cannot animate these properties (or any other properties of type double) if they are by default unset.

Here is a snippet that shows the code that would raise this kind of exception

   1: <Border Background="Red" HorizontalAlignment="Center" VerticalAlignment="Center">

   2:    <TextBlock Text="CLICK ME" VerticalAlignment="Center" HorizontalAlignment="Center"/>

   3:    <Border.Triggers>

   4:        <EventTrigger RoutedEvent="UIElement.MouseDown">

   5:            <BeginStoryboard>

   6:                <Storyboard>

   7:                    <DoubleAnimation Storyboard.TargetProperty="Height" To="300"/>

   8:                </Storyboard>

   9:            </BeginStoryboard>

  10:        </EventTrigger>

  11:    </Border.Triggers>

  12: </Border>

When you try to do this you get an exception like this one

>> Cannot animate the ‘Height’ property on a ‘System.Windows.Controls.Border’ using a ‘System.Windows.Media.Animation.DoubleAnimation’. For details see the inner exception.

and same for Width.

What I do in order to achieve the same behaviour without the need of setting a default width and height is to use a Scale Transform instead. Here is a snippet to get the same behaviour as the XAML above to animate the height

   1: <Border Background="Red" HorizontalAlignment="Center" VerticalAlignment="Center">

   2:    <TextBlock Text="CLICK ME" VerticalAlignment="Center" HorizontalAlignment="Center"/>

   3:    <Border.RenderTransform>

   4:        <ScaleTransform ScaleX="1" ScaleY="1" />

   5:    </Border.RenderTransform>

   6:    <Border.Triggers>

   7:        <EventTrigger RoutedEvent="UIElement.MouseDown">

   8:            <BeginStoryboard>

   9:                <Storyboard>

  10:                    <DoubleAnimation Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)" To="2"/>

  11:                </Storyboard>

  12:            </BeginStoryboard>

  13:        </EventTrigger>

  14:    </Border.Triggers>

  15: </Border>

Please note that there is a catch here. By using scale transform everything inside the actual control will be scaled. So if that is not what you want then you have a problem.

Yet of course there are solutions…. One of the solutions is to have an attached property to set the Height for you when the control is loaded. This can be achieved by setting the Height/Width to the ActualHeight/ActualWidth. Here is an attached property that I use in such cases.

   1: #region SetHeightToActual

   2:  

   3: /// <summary>

   4: /// SetHeightToActual Attached Dependency Property

   5: /// </summary>

   6: public static readonly DependencyProperty SetHeightToActualProperty =

   7:     DependencyProperty.RegisterAttached("SetHeightToActual", typeof(bool), typeof(WidthHeightBehaviour),

   8:         new FrameworkPropertyMetadata((bool)false,

   9:             new PropertyChangedCallback(OnSetHeightToActualChanged)));

  10:  

  11: /// <summary>

  12: /// Gets the SetHeightToActual property.  This dependency property 

  13: /// indicates ....

  14: /// </summary>

  15: public static bool GetSetHeightToActual(DependencyObject d)

  16: {

  17:     return (bool)d.GetValue(SetHeightToActualProperty);

  18: }

  19:  

  20: /// <summary>

  21: /// Sets the SetHeightToActual property.  This dependency property 

  22: /// indicates ....

  23: /// </summary>

  24: public static void SetSetHeightToActual(DependencyObject d, bool value)

  25: {

  26:     d.SetValue(SetHeightToActualProperty, value);

  27: }

  28:  

  29: /// <summary>

  30: /// Handles changes to the SetHeightToActual property.

  31: /// </summary>

  32: private static void OnSetHeightToActualChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)

  33: {

  34:     if ((bool)e.NewValue)

  35:     {

  36:         var element = (FrameworkElement)d;

  37:         RoutedEventHandler handler = null;

  38:         handler = delegate

  39:         {

  40:             element.Height = element.ActualHeight;

  41:             element.Loaded -= handler;

  42:         };

  43:         element.Loaded += handler;

  44:     }

  45: }

  46:  

  47: #endregion

And here is the XAML where I am using the attached behaviour. It is nearly seamless

   1: <Border Background="Red" HorizontalAlignment="Center" VerticalAlignment="Center" local:WidthHeightBehaviour.SetHeightToActual="True">

   2:    <TextBlock Text="CLICK ME" VerticalAlignment="Center" HorizontalAlignment="Center"/>

   3:    <Border.Triggers>

   4:        <EventTrigger RoutedEvent="UIElement.MouseDown">

   5:            <BeginStoryboard>

   6:                <Storyboard>

   7:                    <DoubleAnimation Storyboard.TargetProperty="Height" To="300"/>

   8:                </Storyboard>

   9:            </BeginStoryboard>

  10:        </EventTrigger>

  11:    </Border.Triggers>

  12: </Border>

You can do the same thing for the Width or any other property of this kind (for example I use this technique also for Center property of ScatterViewItems in Surface development).

Hope this tip/trick helps 🙂

Happy coding

Service Locator in MVVM

While doing MVVM one of the common problems to solve is to have the ViewModel consume entities that are “replaceable”. Let me give you an example so that you can better understand what I mean by “replaceable“. Let’s say you have a ViewModel that is using a DataAccess entity to get some data from a data store. You want to be able replace the DataAccess entity so that you can mock this entity for unit testing. Besides this you want to also be able to have some sample data while at design time. And not to forget, when at runtime you want the data access to connects to the database or whatever data store you are using.

In order to do solve this problem I use the ServiceLocator pattern. The Service Locator pattern is very simple. You have a RegisterService method where you register the instance of the service you want to provide and a GetService method which you would use to get the service you want.

Here is the signature of both methods

   1: public T GetService<T>()

   2:  

   3: public bool RegisterService<T>(T service)

And here is how to use them in code

   1: //get the data access service

   2: var dataAccess = GetService<IPeopleDataAccess>();

   3:  

   4: //Register the data access service

   5: vm.ServiceLocator.RegisterService<IPeopleDataAccess>(new PeopleDataAccess());

So for example to test the the ViewModel I can write a unit test like this

   1: MainViewModel viewModel = new MainViewModel();

   2: viewModel.ServiceLocator.RegisterService<IPeopleDataAccess>(new PeopleDataAccessMock());

   3:  

   4: Assert.AreEqual(viewModel.People.Count, PeopleDataAccessMock.PeopleCount,

   5:    "Invalid number of People returned");

   6: Assert.AreEqual(viewModel.People[0].Name, PeopleDataAccessMock.FirstPersonName,

   7:    "Invalid item in people list");

   8: Assert.AreEqual(viewModel.People[0].Surname, PeopleDataAccessMock.FirstPersonSurname,

   9:    "Invalid item in people list");

So basically in this unit test I am just creating a mock object and testing that my ViewModel is exposing the data from the data access (which is mocked so the data returned by this data access is known in the test context)

This is all cool but now how can I use this in WPF and MVVM. So the first question that people ask is how do I create the ViewModel and set it as the DataContext. And also who is responsible of assigning the services that the ViewModel will consume. In order to do this I use AttachedBehaviour and the Factory design pattern.

I created a simple attached property that accepts a type of a Factory that is responsible for creating the ViewModel and register whatever services it needs. The attached property is very simple, here is the code for it

   1: public class ViewModelLoader

   2: {

   3:     #region FactoryType

   4:  

   5:     /// <summary>

   6:     /// FactoryType Attached Dependency Property

   7:     /// </summary>

   8:     public static readonly DependencyProperty FactoryTypeProperty =

   9:         DependencyProperty.RegisterAttached("FactoryType", typeof(Type), typeof(ViewModelLoader),

  10:             new FrameworkPropertyMetadata((Type)null,

  11:                 new PropertyChangedCallback(OnFactoryTypeChanged)));

  12:  

  13:     /// <summary>

  14:     /// Gets the FactoryType property.  This dependency property 

  15:     /// indicates ....

  16:     /// </summary>

  17:     public static Type GetFactoryType(DependencyObject d)

  18:     {

  19:         return (Type)d.GetValue(FactoryTypeProperty);

  20:     }

  21:  

  22:     /// <summary>

  23:     /// Sets the FactoryType property.  This dependency property 

  24:     /// indicates ....

  25:     /// </summary>

  26:     public static void SetFactoryType(DependencyObject d, Type value)

  27:     {

  28:         d.SetValue(FactoryTypeProperty, value);

  29:     }

  30:  

  31:     /// <summary>

  32:     /// Handles changes to the FactoryType property.

  33:     /// </summary>

  34:     private static void OnFactoryTypeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)

  35:     {

  36:         FrameworkElement element = (FrameworkElement)d;

  37:         IFactory factory = Activator.CreateInstance( GetFactoryType(d) ) as IFactory;

  38:         if (factory == null)

  39:             throw new InvalidOperationException("You have to specify a type that inherits from IFactory");

  40:         element.DataContext = factory.CreateViewModel(d);

  41:     }

  42:  

  43:     #endregion

  44:  

  45: }

and you can use this in XAML like so

   1: <Window x:Class="ServiceLocatorSample.Main"

   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   4:     xmlns:vm="clr-namespace:MVVMHelper.Factory;assembly=MVVMHelper"

   5:     xmlns:fac="clr-namespace:ServiceLocatorSample.ViewModels.Factories"

   6:     Title="Main" Height="300" Width="300" vm:ViewModelLoader.FactoryType="{x:Type fac:MainViewModelFactory}">

Usually in the implementation of the factory I would check if the current state is at design time or runtime and accordingly register different services. Something like this

   1: public class MainViewModelFactory : IFactory

   2: {

   3:    public object CreateViewModel(DependencyObject sender)

   4:    {

   5:        var vm = new MainViewModel();

   6:        if (Designer.IsDesignMode)

   7:            vm.ServiceLocator.RegisterService<IPeopleDataAccess>(new DesignTimeData.DesignTimePeopleDataAccess());

   8:        else

   9:            vm.ServiceLocator.RegisterService<IPeopleDataAccess>(new PeopleDataAccess());

  10:        return vm;

  11:    }

  12: }

So with this factory at design time I would get Design time data showing in my designer but as soon as I run the app the actual data access (the real one that connects to the database) gets injected.

That’s it for today. Download the sample project and you will have a better idea of how all this works. Any questions or comments please let me know, I will be more than happy to answer 🙂

P.S In the sample I have the full MVVMHelper assembly that I use in my everyday work with MVVM so you will also have stuff like Mediator and other things that I will be blogging about very soon 🙂

Download the sample project