... a journey through WPF, MVVM and .NET4 RSS 2.0
# Thursday, January 28, 2010

The main project I’ve been working on the past few months has been a rRNA sequencing application.  It’s a joint project involving Microsoft Research and the University of Texas in Austin.  The goal being to produce lightning fast visualizations (nucleotide, 2D and 3D) with very large (100,000 sequence) data sets on WPF.  It’s been a big learning experience for me in many ways because the traditional mechanisms for dealing with things in WPF just flat out fail when we load big datasets and start scrolling them around.  So, we’ve had to invent data virtualization schemes, our own UI virtualization for scrolling, several custom controls and a variety of other elements to pull it off so far.  rCAT 4.0 (coming in March) is even more ambitious with editing support for the sequences!

All that said, our current effort is now online with full source code – it’s interesting stuff to browse through even if you aren’t into molecular biology – check it out at http://rcat.codeplex.com/

Here’s a nice screen shot showing some of the elements – dockable tabs and sidebar items, birds-eye viewer, taxonomy viewer and custom colorization of nucelotide data.  And it, of course, is all MVVM.  Fun stuff!

CATUI.Overview.Shrink

Thursday, January 28, 2010 2:58:46 PM (Central Standard Time, UTC-06:00)  #    Comments [0] -
.NET | MVVM | WPF

I know I said I was going to cover some services next, but I got a request last night to show how to rename TreeView nodes (ala Explorer) using the MVVM pattern in WPF.  The solution is quite easy and elegant and I thought I’d share it here.

First, the idea is we want to be able to double-click on the text portion of the TreeViewItem and have it allow us to type in a new name, replacing the current text.  This involves changing the visual template out (from a TextBlock to a TextBox) and then detecting that the edit is complete.

I started with the MVVM project template, creating the default File Explorer view.  The TreeView on the left is displaying folders – so I opened the DirectoryViewModel.cs that drives the data.

First, let’s add a property to indicate whether we are in “editing” mode or not.  This is a simple field-backed property that raises the PropertyChange notification:

/// <summary>

/// True/False whether we are changing the name of the directory

/// </summary>

public bool IsEditingName

{

   get { return _isEditingName; }

   set { _isEditingName = value; OnPropertyChanged("IsEditingName"); }

}


I also added the private field (_isEditingName) into the class.  Next, locate the Name property that is being used to display the name.  Here we need to add a setter that renames the directory.  We want it to be robust, so we do some upfront checks and make sure to catch any I/O exceptions that occur:

/// <summary>

/// Name of the directory

/// </summary>

public string Name

{

   get { return _data.Name; }

 

   // Code to rename directory

   set

   {

      string newValue = value;

      if (!string.IsNullOrEmpty(newValue))

      {

         // Remove any trailing backslash.

         string fullName = _data.FullName.TrimEnd(Path.DirectorySeparatorChar);

 

         // Determine the new directory name

         string directoryPath = fullName.Substring(0, fullName.Length - _data.Name.Length);

         if (!string.IsNullOrEmpty(directoryPath) && directoryPath != fullName)

         {

            string newFullName = Path.Combine(directoryPath, newValue);

            try

            {

               _data.MoveTo(newFullName);

            }

            catch (IOException ex)

            {

               var errorVisualizer = Resolve<IErrorVisualizer>();

               if (errorVisualizer != null)

               {

                  errorVisualizer.Show("Cannot rename directory", ex.Message);

               }

            }

         }

      }

      // Tell WPF the name has changed.  Note if the same control

      // is being used to display vs. edit then the

      // binding will need to force WPF3x to re-read the property value. 

      // This is done by using a RefreshValueConverter;

      // under .NET4 this won't be necessary.

      OnPropertyChanged("Name");

 

     // Flip off the editing bit

     IsEditingName = false;

  }

}


Notice how changes the editing flag at the end – we assume that once the rename has occurred we are out of editing mode.  Finally, we need a way to transition from “normal” to “edit” mode and back.  In the VM these kinds of things are driven with commands – so, let’s define an ICommand that takes us in and out of edit mode:

/// <summary>

/// Command used to switch to editing mode

/// </summary>

public ICommand SwitchToEditingMode { get; private set; }


And then finally initialize it in the default constructor – we also now need to chain to that constructor from the parameterized version since we always want this initialization to happen (you could also do the initialization in both, but I prefer this approach):

/// <summary>

/// Constructor for the marker directory.  This is used to detect an expansion.

/// </summary>

private DirectoryViewModel()

{

   // Command that switches us into editing mode.

   SwitchToEditingMode = new DelegatingCommand(

                 () => IsEditingName = !IsEditingName,

                 () => _data.FullName != _data.Name);

}

 

/// <summary>

/// Public constructor

/// </summary>

/// <param name="di">DirectoryInfo to pull information from</param>

public DirectoryViewModel(DirectoryInfo di) : this()

{

...

}


That’s all the code changes we need for this – now let’s switch to the View and see how we will wire this up!  Open the MainWindow.xaml file and look at the DataTemplate used by the TreeView.  All of our changes will go into this template. First, we need to add a TextBox into the template that sits in the same space as the TextBlock that displays the name.  Then we need some way to switch between these two elements – I use Visibility here, you could also swap out the entire template.  We’ll use a DataTrigger and drive it off our new IsEditingName property:

<HierarchicalDataTemplate x:Key="DirectoryTemplate" ItemsSource="{Binding Subdirectories}">

   <StackPanel Orientation="Horizontal">

      <Image Width="16" Height="16"

          Source="{Binding FullName, Converter={StaticResource iconConverter}}" />

      <Grid Margin="5,0">

         <TextBlock x:Name="tb" Text="{Binding Name}" />

         <!-- Editing text box -->

         <TextBox x:Name="etb" Visibility="Collapsed" MinWidth="100"

              Text="{Binding Name, UpdateSourceTrigger=LostFocus,

                     Converter={julmar:RefreshValueConverter}}" />

      </Grid>

   </StackPanel>

   <HierarchicalDataTemplate.Triggers>

      <DataTrigger Binding="{Binding IsSelected}" Value="True">

         <Setter TargetName="tb" Property="FontWeight" Value="Bold" />

      </DataTrigger>

      <!-- When editing mode is turned on, get rid of the TextBlock and

           make the TextBlock visible. -->

      <DataTrigger Binding="{Binding IsEditingName}" Value="True">

         <Setter TargetName="tb" Property="Visibility" Value="Collapsed" />

         <Setter TargetName="etb" Property="Visibility" Value="Visible" />

      </DataTrigger>

   </HierarchicalDataTemplate.Triggers>

</HierarchicalDataTemplate>

 

The other thing we need to do is set the TextBox binding (which also uses the Name property) to apply any changes when the control loses focus – that way we don’t rename as the user types!  This is done by changing the UpdateSourceTrigger on the binding to “LostFocus”. This happens to be the default setting for WPF – but not for Silverlight, so I tend to be deliberate when I want to ensure a specific behavior.  I’ve also added a converter onto the binding above – the RefreshValueConverter.  This is a no-op converter, but it forces WPF to re-read the property value after the setter is called, without it, the TextBox will have stale data if the rename fails.  Note that this is unnecessary in WPF4 which now always re-reads the property values automatically.  Since this targets WPF3.5, this converter will ensure proper behavior.

The final thing we need to do is somehow get in and out of editing mode.  We want this to happen when we double-click on the text element – so let’s add a JulMar behavior and action to the TextBlock:

<TextBlock x:Name="tb" Text="{Binding Name}">

   <Interactivity:Interaction.Triggers>

      <!-- DoubleClick activates editing mode -->

      <julmar:DoubleClickTrigger>

         <julmar:InvokeCommand Command="{Binding SwitchToEditingMode}" />

      </julmar:DoubleClickTrigger>

   </Interactivity:Interaction.Triggers>

</TextBlock>


This also requires you define the proper namespace on the Window element:

xmlns:Interactivity="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"


I’d also like to drop out of editing mode when you press ENTER in the TextBox. To accomplish this, let’s add an InputBinding to the TextBox for the ENTER key that invokes our SwitchToEditingMode command – in WPF 3.5 we need to go through a resource-based binding helper to get access to the ViewModel (which is our DataContext).  So, let’s defined a BindableCommand in the Grid resources (so we get the DirectoryViewModel as the DataContext) and then bind the input command to that:

<Grid.Resources>

<!-- Put here so it inherits the data context properly.  We want the command to execute on

     directory view model -->

   <julmar:BindableCommand x:Key="EditingModeCommand"

        Command="{Binding SwitchToEditingMode}" />

</Grid.Resources>

<TextBox x:Name="etb" Visibility="Collapsed" MinWidth="100"

   Text="{Binding Name, UpdateSourceTrigger=LostFocus,

           Converter={julmar:RefreshValueConverter}}">

   <!-- Pressing ENTER in the TextBox turns off editing mode. 

        Tab or clicking away will do the same thing -->

   <TextBox.InputBindings>

      <KeyBinding Key="Enter" Command="{StaticResource EditingModeCommand}" />

   </TextBox.InputBindings>

</TextBox>


And that’s it!  If you run the app and double-click on a directory name (except the root) you can rename it!

RenameTreeNodePic

Here’s the finished solution: RenameTreeNode.zip

Thursday, January 28, 2010 11:13:52 AM (Central Standard Time, UTC-06:00)  #    Comments [2] -
.NET | MVVM | WPF
# Wednesday, January 27, 2010

In this post, we’ll explore the service locator (called ServiceProvider in the library) and introduce the specific services included with the MVVM Helper library (as of 1.05 anyway). 

What is the Service Locator?

In a nutshell, the service locator is a resolver for services that your application might need or use.  It relates a type key to a specific object implementation.  This is nothing new – the service locator design pattern has been around forever and is considered a core J2EE pattern (see ServiceLocator.html for that definition).  In the MVVM Helpers library, this pattern is implemented in the JulMar.Windows.Mvvm.ServiceProvider class in JulMar.Wpf.Helpers.dll.  In retrospect, I’d prefer it be in a different namespace, but that’s where I stuck it initially.  Here’s what it looks like:

ServiceProviderDefinition

Notice that it implements the IServiceProvider interface – this is a base .NET interface used for service resolution and a form of it can be found in the Visual Studio extensibility API, Windows Workflow and a variety of other projects.  The basis for the interface is you call the GetService method, passing a System.Type (generally an interface or abstract class type) and it returns the concrete implementation if the resolver knows about it.  This model allows the host to decide what the concrete implementation should be – for example in the Workflow world, the system needs to treat output completely differently for a Console App vs. a web application.  So, a console host might add a service for output that prints a string to the console window, while a web application might define the same service as a redirection to an output page.

Ok, I get that, now how do I use it?

It’s easy.  From a client perspective, you simply request a service using the interface or class key.  As an example, in the previous post I mentioned the IMessageVisualizer interface which allows a ViewModel to popup a message box to notify the user about something.  Given that the VM is supposed to be somewhat technology agnostic and unit testable, we want to hide the implementation of displaying output behind an interface and that’s exactly what IMessageVisualizer is for.  To get the concrete implementation, we ask the ServiceProvider.  To do that, we need to define an instance of a provider – each instance has it’s own private collection of services that it manages.

For simplicity, the base JulMar.Windows.Mvvm.ViewModel class defines a public static ServiceProvider property:

public class ViewModel : SimpleViewModel, IDisposable

{

   /// <summary>

   /// Service resolver for view models.  Allows derived

   /// types to add/remove

   /// services from mapping.

   /// </summary>

   public static readonly ServiceProvider ServiceProvider;


This property can be accessed anywhere in your project and it’s the specific instance that the default services are registered in (more on that in a second).  To get the message visualizer you could do this:

var messageVisualizer = ViewModel.ServiceProvider.GetService(typeof(IMessageVisualizer)) as IMessageVisualizer;

if (messageVisualizer != null)

{

   // Use message visualizer

}


This invokes the IServiceProvider.GetService method to retrieve the service. Since that’s somewhat verbose, there is a typed helper method that cuts down your keystrokes and casts the return type automatically:

var messageVisualizer = ViewModel.ServiceProvider.Resolve<IMessageVisualizer>();

As a shortcut, if you are deriving from the ViewModel base class it provides a convenience Resolve<T> method that cuts it to:

var messageVisualizer = Resolve<IMessageVisualizer>();

Notice the null check to see if the service exists?  This is because services are dynamic, you register services with the service provider – so if the type key has not been registered the Resolve will return null to indicate an unsupported service.

Service Registration

That brings us to registering and unregistering services.  This is accomplished through the ServiceProvider.Add and ServiceProvider.Remove methods:

public class ServiceProvider : IServiceProvider

{

   /// <summary>

   /// Adds a new service to the resolver list

   /// </summary>

   /// <param name="type">

   /// Service Type (typically an interface)</param>

   /// <param name="value">Object that implements service</param>

   public void Add(Type type, object value);

   /// <summary>

   /// Remove a service

   /// </summary>

   /// <param name="type">Type to remove</param>

   public void Remove(Type type);

}


The Add method takes a type – you want to use an interface or abstract/virtual base class for extensibility, and an object that implements that interface/base class.

Once the type is registered, future calls to GetService (or Resolve<T>) will return the given object instance.  Note that some implementations of this pattern allow for lazy instantiation and per-call instance services (i.e. where you get a unique instance on each call to GetService).  I’ve not found a need for either of these and so this implementation is very simple.  Thinking about it, I’d probably register an instance that has a method to create the per-call items I need anyway.

The Remove method takes the type key and throws away the instance it is associated with – future calls made to retrieve the service will return null.

An Example: Spell Checking

Say for instance you needed a spell checking service for your application, and multiple ViewModels (and perhaps even view code behind files) will need access to it.  You could use the ServiceProvider to cache off your service and then access that instance as a singleton anywhere in your application – or even in other modules that are aware of the interface type.  That’s the idea behind this pattern, it allows you to loosely connect things together and bind them at runtime very easily.

So, first, I’d define a spell checking service interface (note this is an example so I’m keeping it very simple):

public interface ISpellCheckService

{

   bool CheckSpelling(string text);

}


Next, I’d have some concrete implementation of the above interface.  Let’s pretend I called it DictionarySpellChecker.  Then, somewhere in my application I add this service to the ServiceProvider, I might do this in my Application class:

public partial class App

{

   public App()

   {

      // Register the spell checker service

      ViewModel.ServiceProvider.Add(typeof(ISpellCheckService),

                    new DictionarySpellChecker());

   }

}


Then, any class that needs access to the spell check service simply needs to access the proper ServiceProvider:

var spellChecker = ViewModel.ServiceProvider.Resolve<ISpellCheckService>();

Creating your own ServiceProvider instance

Note that here I’m using the ViewModel’s service provider – but that’s just because I know it’s there.  You can use the service provider independently of the ViewModel class.  All you need to do is:

  1. Create an instance of the ServiceProvider class
  2. Register your services against that specific instance
  3. Make the instance available to anyone who needs the services (i.e. through a singleton property.

You can create as many service providers as you need to encapsulate your services.

Built in services

The last thing I want to touch on are the built in services in the MVVM Helper library.  There are several services that can be registered, used or replaced in the library for your convenience.  In future blog posts I will detail each service specifically, but I’ll mention them here because they use the ServiceProvider as a resolver.

In the project template it registers all the services through a static method call – this is done in the Application constructor:

public partial class App

{

   public App()

   {

      // Register the typical services (UI, Error, etc.)

      ViewModel.RegisterKnownServiceTypes();

       ...

   }

}


This call to ViewModel.RegisterKnownServiceTypes is required to use the built-in services; without it, none of them are registered.  If you look into the ViewModel source code, the definition for this method is:

/// <summary>

/// This method registers known WPF services with the

/// service provider.

/// </summary>

public static void RegisterKnownServiceTypes()

{

   ServiceProvider.Add(typeof(IErrorVisualizer),

                       new ErrorVisualizer());

   ServiceProvider.Add(typeof(IMessageVisualizer),

                       new MessageVisualizer());

   ServiceProvider.Add(typeof(INotificationVisualizer),
                       new NotificationVisualizer());

   ServiceProvider.Add(typeof(IUIVisualizer), new UIVisualizer());

   ServiceProvider.Add(typeof(IMessageMediator),

                       new MessageMediator());

}


As you can see, it’s just doing what what you would expect – registering a specific implementation for each service interface type.  The services are:

Service Interface Description
IErrorVisualizer Presents an error dialog as a MessageBox with an OK button to dismiss it.
IMessageVisualizer Presents a message dialog as a MessageBox with a selectable button set.
INotificationVisualizer Allows long-running modal operations to present some wait notification (defaults to changing the cursor to an hourglass).
IUIVisualizer Presents a custom modal or modeless dialog to the user associated with a ViewModel.
IMessageMediator Message transfer service that allows loosely connecting ViewModels together.


Replace services

Each service interface has a default implementation registered against it.  If you don’t like the implementation, or prefer to have your own custom implementation, simply add the service again after it was registered.

public partial class App

{

   public App()

   {

      // Register the typical services (UI, Error, etc.)

      // for this application.

      ViewModel.RegisterKnownServiceTypes();

 

      // Replace the notification visualizer with our cool version..

      ViewModel.ServiceProvider.Add(
           typeof(INotificationVisualizer), new NotifyWaitBox());

   }

}


This will replace the default instance with a new provider – any future calls to retrieve the service will return your new instance.  This can be done at any time, and as many times as you like (as an example, consider a theme service you dynamically replace at runtime as the user selects the theme).

Final Warnings

There is one warning I need to impart on the service locator.  It holds hard references to the registered instances.  That means if you want the instance to be Garbage Collected prior to the application terminating, you must remove the key from the service provider. This normally isn’t an issue as most services are lifetime services and are intended to be around until the end, but if you are using a transient service and only need it for a short period please remember this point so you don’t create an unintentional memory “leak”.

In the next post we’ll cover the Message, Error and Notification visualization services.  Stay tuned MVVM fans!

Wednesday, January 27, 2010 11:25:00 AM (Central Standard Time, UTC-06:00)  #    Comments [2] -

# Friday, January 22, 2010

In the previous post, I provided a link to the project template you can use to start a new MVVM project using the JulMar MVVM library. Here's the two links in case you didn't get them before:

MVVM Helpers Distribution
Project Template

Copy the project template into your Visual Studio 2008 templates directory located off your user documents - mine is at %UserProfile%\Documents\Visual Studio 2008\Templates\ProjectTemplates\Visual C#\Windows.

Ok, so once you have these installed, what can you do with them? Well, for starters, you can now generate a starter project that provides a nice template for an MVVM application. The starter template creates a simple "Explorer" like program - it looks like this:

Notice there are two sections - a TreeView listing all the directories, and a ListView showing all the files in the selected directory. Let's look a little closer at the project structure. There are four directories in the solution:

Converters This has a simple ValueConverter that takes a filename and returns an icon as an ImageSource.
Dependencies This is the binary dependencies the project requires, specifically it contains the JulMar MVVM libraries and Blend action libraries.
ViewModels This directory contains all the business logic in the form of ViewModels.
Views Finally, this directory contains all the UI (XAML) for the application.

Views

Let's start with the last folder - the Views. Views are the UI presentation of data - in the case of a WPF/Silverlight application this is most commonly the XAML and XAML code behind files (they are considered a single element together). We want to have UI-specific code and designer elements present in these files. Generally we prefer to place business logic and testable elements into the ViewModel area.

In this starter project, we have a single view MainWindow.xaml. This is what presents the main UI shown above. The code behind file contains the required boilerplate code (essentially a constructor and call to InitializeComponent).

If you open the view (note that the designer will choke on it until you compile the project), you will find fairly straightforward XAML that creates the UI, let’s break it down as we go:

<Window x:Class="WpfMVVMApplication1.Views.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:julmar="http://www.julmar.com/wpfhelpers"
    xmlns:ViewModels="clr-namespace:WpfMVVMApplication1.ViewModels"
    xmlns:Converters="clr-namespace:WpfMVVMApplication1.Converters"
    DataContext="{julmar:ViewModelCreator {x:Type ViewModels:MainViewModel}}"
    Title="File Explorer" Height="400" Width="500">

 

First, notice how the DataContext is established – through a custom MarkupExtension called ViewModelCreator.  This extension is responsible for creating an associated ViewModel for this view (where our testable business logic should go) and also wiring up a couple of special event handlers that will allow the ViewModel to activate the view and close the view respectively.

Next, let’s check out the resources:

<Window.Resources>

  <!-- Bindable commands sit in resources and allow keyboard input to target ViewModel commands -->

  <julmar:BindableCommand x:Key="CloseCommand" Command="{Binding CloseAppCommand}" />

  <Converters:FilenameToIconConverter x:Key="iconConverter" />

  <HierarchicalDataTemplate x:Key="DirectoryTemplate"

           ItemsSource="{Binding Subdirectories}">

     <StackPanel Orientation="Horizontal">

        <Image Width="16" Height="16" Source="{Binding FullName,

               Converter={StaticResource iconConverter}}" />

        <TextBlock x:Name="tb" Margin="5,0" Text="{Binding Name}" />

     </StackPanel>

     <HierarchicalDataTemplate.Triggers>

        <DataTrigger Binding="{Binding IsSelected}" Value="True">

           <Setter TargetName="tb" Property="FontWeight" Value="Bold" />

        </DataTrigger>

     </HierarchicalDataTemplate.Triggers>

  </HierarchicalDataTemplate>

</Window.Resources>


Here we find three defined resources – first we have a JulMar MVVM BindableCommand.  This is a special ICommand instance that can be data bound and forwards to the specified binding.  We use this a bit later in the keyboard accelerator to close the application.  Next, there is the converter that takes a filename and converts it to an icon – that’s the source code in the Converters folder mentioned earlier.  I use a converter here because this is very UI-centric and not very testable – so the converter will data bind to a string (filename) property of the ViewModel and retrieve the icon for the UI to display.  That way, my ViewModel sticks with base (non-WPF) types.  This isn’t a hard rule – but it’s a good one to try to follow.

Finally, there is a DataTemplate that is used to display the directory structure – this is what the TreeView uses to display it’s data.  Notice it data binds to a couple of properties – FullName, Name and IsSelected.  All of these, as you will see, exist in our ViewModel definition.  The View takes the data from the ViewModel and displays it onto the UI for the user to interact with.

Next in the XAML is the input bindings – this is where we define keyboard and mouse gesture accelerators, and it’s where I use the bindable command I defined earlier:

    <Window.InputBindings>

        <KeyBinding Key="X" Modifiers="ALT" Command="{StaticResource CloseCommand}" />

    </Window.InputBindings>

 

Here you can see that instead of trying to bind to the command, we use {StaticResource} to get it from the resources.  This is necessary under WPF 3.5 because the KeyBinding will not inherit the DataContext and so cannot bind directly to the command – but resources can, and specifically Freezable resources can – that’s what the BindableCommand provides – a Freezable resource that forwards the ICommand implementation onto a command defined in the DataContext ViewModel.  This is not necessary under WPF4 – this is actually one of the new features they’ve added: to inherit the DataContext in your input bindings! 

The remainder of the view is fairly traditional – we use bindings to connect the UI up to the ViewModel definitions, so let’s go look at what those are.

ViewModels

The ViewModel folder contains three source code files – DirectoryViewModel.cs, FileViewModel.cs, and MainViewModel.cs.  If you recall from above, MainViewModel is the primary ViewModel that is data bound to the view.  The other two are child view models used to represent the files and folders respectively.  Let’s look at FileViewModel as an example:

    public class FileViewModel : SimpleViewModel

    {

        /// <summary>

        /// Marker file that signals expansion of the tree.

        /// </summary>

        internal static FileViewModel MarkerFile = new FileViewModel();

 

        private readonly FileInfo _data;

 

        /// <summary>

        /// File name

        /// </summary>

        public string Name

        {

            get { return _data.Name; }

        }

 

        /// <summary>

        /// Full path + filename

        /// </summary>

        public string FullPath

        {

            get { return _data.FullName; }

        }

 

        /// <summary>

        /// Size of the file in bytes

        /// </summary>

        public long Size

        {

            get { return _data.Length; }

        }

 

        /// <summary>

        /// Private constructor used to create marker file.

        /// </summary>

        public FileViewModel()

        {

        }

 

        /// <summary>

        /// Public constructor that captures a list of files.

        /// </summary>

        /// <param name="fi">FileInfo to grab file information from</param>

        public FileViewModel(FileInfo fi)

        {

            _data = fi;

        }

    }

 

As you can see, it is very simple – it is simply a wrapper around a piece of data, a FileInfo that represents a file on disk.  It exposes properties that are data bindable.  There is one element (MarkerFile) that I want you to ignore for a moment – we’ll get to it in a second.  Notice that it extends SimpleViewModel.  This is one of three primary VM classes in the MVVM helper library.  SimpleViewModel is intended for cases where you need the bare minimum support – specifically support for INotifyPropertyChanged.  No other services are provided by this base class, and as such it is very light.  Let’s look at the directory class next:

    /// <summary>

    /// Sample ViewModel that wraps a Directory.

    /// </summary>

    public class DirectoryViewModel : ViewModel

    {

        /// <summary>

        /// String used to send message to main view model about directory selection.

        /// </summary>

        internal const string SelectedDirectoryChangedMessage = @"SelectedDirectoryChanged";

 

        /// <summary>

        /// Marker directory that signals expansion of the tree.

        /// </summary>

        internal static DirectoryViewModel MarkerDirectory = new DirectoryViewModel();

 

        private bool _isSelected, _isExpanded;

        private readonly DirectoryInfo _data;

        private readonly ObservableCollection<FileViewModel> _files;

        private readonly ObservableCollection<DirectoryViewModel> _subdirs;

 

        /// <summary>

        /// Name of the directory

        /// </summary>

        public string Name

        {

            get { return _data.Name; }

        }

 

        /// <summary>

        /// Full path + name of the directory

        /// </summary>

        public string FullName

        {

            get { return _data.FullName; }

        }

 

        /// <summary>

        /// True/False whether the directory is selected (i.e. current).

        /// Selecting the directory causes it to populate it's file collection.

        /// </summary>

        public bool IsSelected

        {

            get { return _isSelected; }

            set

            {

                if (_isSelected != value)

                {

                    _isSelected = value;

 

                    if (_isSelected)

                    {

                        if (_files.Count == 1 && _files[0] == FileViewModel.MarkerFile)

                        {

                            _files.Clear();

                            _data.GetFiles()

                                .Where(f => (f.Attributes & (FileAttributes.Hidden | FileAttributes.System)) == 0)

                                .ForEach(f => _files.Add(new FileViewModel(f)));

                            OnPropertyChanged("TotalFiles", "TotalFileSize");

                        }

                        SendMessage(SelectedDirectoryChangedMessage, this);

                    }

                    else

                    {

                        _files.Clear();

                        _files.Add(FileViewModel.MarkerFile);

                    }

 

                    OnPropertyChanged("IsSelected");

                }

            }

        }

 

        /// <summary>

        /// True/False if the directory is expanded. Expanding the directory causes it

        /// to fill it's subdirectory collection.

        /// </summary>

        public bool IsExpanded

        {

            get { return _isExpanded; }

            set

            {

                if (_isExpanded != value)

                {

                    _isExpanded = value;

                    if (_isExpanded)

                    {

                        if (_subdirs.Count == 1 && _subdirs[0] == DirectoryViewModel.MarkerDirectory)

                        {

                            _subdirs.Clear();

                            _data.GetDirectories()

                                .Where(d => (d.Attributes & (FileAttributes.Hidden | FileAttributes.System)) == 0)

                                .ForEach(d => _subdirs.Add(new DirectoryViewModel(d)));

                        }

                    }

                    // Throw them away to recollect later - implements a refresh.

                    else

                    {

                        _subdirs.Clear();

                        _subdirs.Add(DirectoryViewModel.MarkerDirectory);

                    }

                }

 

                OnPropertyChanged("IsExpanded");

            }

        }

 

        /// <summary>

        /// List of files in this directory.

        /// </summary>

        public IList<FileViewModel> Files { get { return _files; } }

 

        /// <summary>

        /// List of subdirectories in this directory.

        /// </summary>

        public IList<DirectoryViewModel> Subdirectories { get { return _subdirs; } }

 

        /// <summary>

        /// Count of files in this directory.

        /// </summary>

        public int TotalFiles { get { return _files.Count; } }

 

        /// <summary>

        /// Total size of all files in this directory.

        /// </summary>

        public long TotalFileSize { get { return _files.Sum(file => file.Size); } }

 

        /// <summary>

        /// Constructor for the marker directory.  This is used to detect an expansion.

        /// </summary>

        private DirectoryViewModel()

        {

            _data = null;

        }

 

        /// <summary>

        /// Public constructor

        /// </summary>

        /// <param name="di">DirectoryInfo to pull information from</param>

        public DirectoryViewModel(DirectoryInfo di)

        {

            if (di == null)

                throw new ArgumentNullException("di");

 

            _data = di;

            _files = new ObservableCollection<FileViewModel> { FileViewModel.MarkerFile };

            _subdirs = new ObservableCollection<DirectoryViewModel> { DirectoryViewModel.MarkerDirectory };

        }

    }

 

This file is a bit more complicated – like the FileViewModel, this wraps a simple data object (a DirectoryInfo in this case).  Notice that it too exposes properties to provide access to various bits of information.  Here you can see that it is creating new properties such as TotalFileSize which is the sum of all the files sizes in this directory.  That’s one of the jobs of the ViewModel – to provide easily bindable properties for the bits of information we want to display.  In this case, the TotalFiles and TotalFileSize gets displayed in the StatusBar of the window when the directory has files.

Notice that the directory exposes files and subdirectories in ObservableCollections – but they are delay populated.  This is done so that the TreeView comes up quickly and we don’t have to enumerate the entire disk to retrieve the directories and files!  When you expand and collapse the nodes in the tree, it is populating the data.  This is done through the IsExpanded property – if you look back in the View, you will see that the TreeView actually binds the TreeViewItem.IsExpanded to this property:

<TreeView Grid.Column="0" ItemsSource="{Binding RootDirectory}"

        ItemTemplate="{StaticResource DirectoryTemplate}">

   <TreeView.ItemContainerStyle>

      <Style TargetType="TreeViewItem">

         <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />

         <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />

      </Style>

   </TreeView.ItemContainerStyle>

</TreeView>

 

Notice it also binds up the IsSelected property – this is when we populate the files collection.  Since they are observable, they will force the UI to update when new items are added or removed and we see the Explorer effect we desire.

Lastly, before we leave this file, notice that when a directory is selected, it makes a method call to a function called SendMessage:

SendMessage(SelectedDirectoryChangedMessage, this);

It passes a string (the key) and an object (the data).  This is a built-in service of the ViewModel base class and it’s the reason why this ViewModel does not derive from SimpleViewModel, but instead from ViewModel which is the full version.  One of the services provided is a Message Mediator.  This service basically allows you to loosely couple various objects together – we’ll see how the target registers, but for now, just notice the sender – it passes a string key and an object.  Any target registered for the given key will receive the object.  There are several overrides for the message mediator which I’ll detail in a later post.

Ok, let’s switch to the final file – the MainViewModel:

    public class MainViewModel : ViewModel

    {

        private DirectoryViewModel _selectedDirectory;

 

        /// <summary>

        /// Root directory - can be bound to an ItemsControl on the UI.

        /// </summary>

        public DirectoryViewModel[] RootDirectory { get; private set; }

 

        /// <summary>

        /// Selected (active) directory

        /// </summary>

        public DirectoryViewModel SelectedDirectory

        {

            get { return _selectedDirectory; }

            set { _selectedDirectory = value; OnPropertyChanged("SelectedDirectory"); }

        }

 

        /// <summary>

        /// Command to display the About Box.

        /// </summary>

        public ICommand DisplayAboutCommand { get; private set; }

 

        /// <summary>

        /// Command to end the application

        /// </summary>

        public ICommand CloseAppCommand { get; private set; }

 

        /// <summary>

        /// Main constructor

        /// </summary>

        public MainViewModel()

        {

            // Register this instance with the message mediator so it can receive

            // messages from other views/viewmodels.

            RegisterWithMessageMediator();

 

            // Create our commands

            DisplayAboutCommand = new DelegatingCommand(OnShowAbout);

            CloseAppCommand = new DelegatingCommand(OnCloseApp);

 

            // Fill in the root directory from C:

            RootDirectory = new[] { new DirectoryViewModel(new DirectoryInfo(@"C:\")) { IsSelected = true } };

        }

 

        /// <summary>

        /// This method closes the application window.

        /// </summary>

        private void OnCloseApp()

        {

            // Ask the view to close.

            RaiseCloseRequest();

        }

 

        /// <summary>

        /// This method displays the About Box.

        /// </summary>

        private void OnShowAbout()

        {

            // Get the message visualizer service from the service resolver.

            // All services can be replaced, so make sure to check if we have something

            // registered.

            IMessageVisualizer messageVisualizer = Resolve<IMessageVisualizer>();

            if (messageVisualizer != null)

            {

                // Show a message box.

                messageVisualizer.Show("About File Explorer Sample", "File Explorer Sample 1.0", MessageButtons.OK);

            }

        }

 

        /// <summary>

        /// This method is invoked by the message mediator when a DirectoryViewModel is selected.

        /// </summary>

        /// <param name="newDirectory">DirectoryViewModel that is now active</param>

        [MessageMediatorTarget(DirectoryViewModel.SelectedDirectoryChangedMessage)]

        private void OnCurrentDirectoryChanged(DirectoryViewModel newDirectory)

        {

            SelectedDirectory = newDirectory;

        }

    }

 

Here you can see the same basic principle – it exposes properties the UI binds to.  In particular here we see Commands being exposed as properties.  Commands is what drives a UI – it allows a UI to trigger actions in the ViewModel.  We are using two basic commands here – CloseAppCommand and DisplayAboutCommand.  If you look at the constructor, you will see they are backed by a DelegatingCommand object.  This is a common pattern found in almost every MVVM framework out there, but it’s essentially a pair of delegates that are called when the command is checked and when it is invoked.  In our cases here, we always allow the command to execute so we only provide the execution handler (a second parameter would define the typical CanExecute handler).  There are a couple of overrides for this object as well – one that provides type safety for the parameter and one that always uses object and allows for any object as data.  Again here we are being simple and not using any parameters so our bound methods are both no-parameter methods.

The CloseAppCommand command invokes the OnCloseApp method – which in turn calls RaiseCloseRequest.  This JulMar ViewModel method will close the view associated with the ViewModel if you associated the two using the ViewModelCreator.

The OnShowAbout method is called by the DisplayAboutCommand.  It uses another registered service in the library called IMessageVisualizer.  The message visualizer is used to display a simple message box from the ViewModel.  Here we use it to display an about box.  There are several other services I’ll talk about in the next post.

Notice that the RootDirectory property which is data bound to the TreeView.ItemsSource is exposes as an array – this is because the TreeView always expects a collection of items even though we always have a single root item.  So we wrap a single DirectoryViewModel into a collection and return it as the property.

If you look at the end of the file you will find our message mediator target – OnCurrentDirectoryChanged.  We use this as a way to see when a new directory has been selected in the tree.  For a ListBox, we could  have just data bound the SelectedItem to the property, but TreeView isn’t a selector and doesn’t expose a SelectedItem property.  Instead you either have to catch an event (I’ll show how you can do that in a future blog entry about the MVVM helpers library) or use this little mediator trick.

The [MessageMediatorTarget] attribute is the secret sauce here – it tells the message mediator to wire this method up to the passed string key.  When that key is used in a SendMessage call and the parameter type is a DirectoryViewModel (or derived type), the mediator will invoke this method.  This all happens without any direct linkage between the DirectoryViewModel and the MainViewModel.  The delegate instance is held in a weak reference so there’s no concern for memory leaks.

The second part of the magic is in the constructor – the message mediator is an opt-in service, so notice the call to RegisterWithMessageMediator().  This is what causes this instance to be noticed by the mediator.  There is a balancing UnregisterWithMessageMediator if you ever want to unhook the instance.  You can also use methods to directly wire up handlers (without attributes).  This is useful when you are dynamically linking things together at runtime vs. compile time.

Well, that covers the basics of the framework Views + ViewModels.  In the next post, I will detail the service registration and basic service mechanism that’s built into the framework for you to use.  Until then, ciao!

Friday, January 22, 2010 4:35:37 PM (Central Standard Time, UTC-06:00)  #    Comments [0] -
.NET | Code | MVVM | WPF
# Wednesday, January 20, 2010
To start off this new series, I have created a MVVM Helpers project template - this is a Visual Studio 2008 template which will create the starter project I will be using as an example. It shows off the primary usage of the MVVM library and has directories and references to required assemblies already established so it's a nice starting point for any MVVM WPF app using the helpers.

Download it from here and copy the zip file into your template directory.

As an example, if your user name was "Mark", like me and you are running Windows 7 it would be:
"C:\Users\Mark\Documents\Visual Studio 2008\Templates\ProjectTemplates\Visual C#\Windows"

Here's what my directory looks like:

templatedir.jpg

With that in place you should be able to fire up Visual Studio 2008 and create a sample MVVM project:

project_screen.jpg

Let it generate a project and the build it -- running the program will give you a simple file explorer using the MVVM design pattern and WPF:

 sample-run1.jpg 

In tomorrow's post, we'll break the sample down and see how I built it. See you then!

 

Wednesday, January 20, 2010 5:35:13 PM (Central Standard Time, UTC-06:00)  #    Comments [0] -
.NET | Code | WPF

With this post I am starting a new series - I hope to be more consistent in posting at least once or twice a week. To that end, I am going to focus on the WPF/MVVM helper library I use daily. I released an earlier version of it onto the web and have gotten a lot of comments which has been great, so I am releasing the latest version which has a lot of changes. So, without further ado, here's the code for you to download and play with, this compiles with Visual Studio 2008 SP1, or with Visual Studio 2010 Beta 2.

mvvmhelpers.zip

Read on for the basics of the project structure and files.

Project Structure

The code is broken into two assemblies: Julmar.Wpf.Helpers and Julmar.Wpf.Behaviors. The helpers assembly contains core WPF helper classes and MVVM support and the behaviors assembly depends on the System.Windows.Interactivity support and provides Blend-based behaviors for a variety of situations.

Building and Usage

There are pre-built assemblies included in the distribution, but you are free to build the source on your own - I don't include the certificate file (so I can tell versions that I have built) but you are free to delete the certificate from the solution or replace it with your own and build your own binaries from the source code. Or you can take any of the source code, modify it however you like and add it directly to your project.

Credits

As with most projects, this library has benefited significantly from the community. The WPF Disciples list on has been a particular source for ideas and even source code. There are some source files in the project that I did not author, or where I took a bit of code and modified it to suit my purposes. I have tried to make sure people get credit where appropriate in the source code itself, if I missed anyone I am truly sorry.

Documentation

As I mentioned earlier, my goal is to produce a set of blog posts that detail how to use the library, but there is also some documentation on each class included in the distribution in the form of a .CHM (Windows Help File). I encourage anyone who wants to use this library to check that out.
Solution.jpg

Wednesday, January 20, 2010 2:22:12 PM (Central Standard Time, UTC-06:00)  #    Comments [2] -
.NET | Code | WPF
# Tuesday, August 11, 2009

One of the new features added to WPF 3.5 SP1 was the ScrollViewer.IsDeferredScrollingEnabled property which allows you to scroll through large amounts of data without taking the actual scrolling hit until the user stops moving the scroll thumb.  This is essential when you have complex visualizations, or if the data itself is virtualized and the load time is expensive.  You can get information on this feature here:

http://msdn.microsoft.com/en-us/library/system.windows.controls.scrollviewer.isdeferredscrollingenabled.aspx

Recently, I was working on a project where I have a Slider that is controlling a grouping option.  When the user changes the slider value, the visuals are regrouped based on the position of the slider itself.  The problem I ran into was it's an expensive operation to do the grouping and if the user tries to quickly drag the slider I ended up doing a whole bunch of non-essential groupings of my data for no reason.  They are expensive enough that the actual drag of the slider was impacted by it - not to mention the CPU and rendering!  So, my initial response in these situations is to turn on asynchronous data binding - that's as simple as throwing the Binding.IsAsync flag.  This essentially causes the binding transfer to occur on a background thread and will often improve responsiveness in situations like this.

In this case, however, it didn't really help because I was still doing all the intermediate calculations.  What I really need is some way to defer the binding transfer until the slider stops. There's no option for that however so I whipped up a simple class which allows me to bind two properties together and place a timer between them to indicate how long it should wait before transferring the Source to the Target.  I could have done it in the code - it's just a timer solution after all, but I wanted something reuseable.

Here's an example usage:

<StackPanel>
   <StackPanel.Resources>
      <DeferredBinder:DeferredBinding x:Key="dbTest" Timeout="1" />
   </StackPanel.Resources>
   <TextBlock x:Name="tb" Text="{Binding Source={StaticResource dbTest}, Path=Target}" FontSize="48pt" HorizontalAlignment="Center" />
   <Slider x:Name="slider" Margin="10" HorizontalAlignment="Center" Width="200" Minimum="0" Maximum="100" Value="{Binding Source={StaticResource dbTest}, Path=Source, Mode=OneWayToSource}" />
</StackPanel>

In this case, the slider's value is transferred 1 second after the final update (i.e. it waits 1 second for the user to stop sliding).

Here's a sample project to try out:

DeferredBindingSample.zip

 

Tuesday, August 11, 2009 5:54:00 PM (Central Daylight Time, UTC-05:00)  #    Comments [0] -
.NET | WPF

I'm a big fan of themes in WPF -- and I think it's great that Microsoft has released a whole set of themes for Silverlight and WPF at www.codeplex.com/wpf

However, in using some of those themes, I've run into an annoying bug in the RadioButton template - specifically, the checked state doesn't always show up initially.  Looking at the template, it turns out to be an easy fix.  The "CheckIcon" is set to an opacity of zero initially (so it's not shown) and then a trigger is used to apply an animation to change the value.  Unfortunately, it looks like the animation is switched - it applies when the checkbox is UNCHECKED vs. CHECKED.  So, two ways to fix it -- either change the initial opacity to "1" for the "CheckIcon" element in the control template, or go to the triggers in the control template for the RadioButton and swap the states so it looks like this:

<Trigger Property="IsChecked" Value="false" />
<Trigger Property="IsChecked" Value="True">
   <Trigger.EnterActions>
      <BeginStoryboard x:Name="CheckedOn_BeginStoryboard" Storyboard="{StaticResource CheckedOn}"/>
   </Trigger.EnterActions>
   <Trigger.ExitActions>
      <BeginStoryboard x:Name="CheckedOff_BeginStoryboard" Storyboard="{StaticResource CheckedOff}"/>
   </Trigger.ExitActions>
</Trigger>
Tuesday, August 11, 2009 11:30:13 AM (Central Daylight Time, UTC-05:00)  #    Comments [3] -
.NET | WPF
# Tuesday, August 04, 2009

I just put the latest version of the MVVM helpers online - mvvmhelpers.zip

There's a bunch of new stuff in it - check the release notes for the highlights.  There's a set of breaking changes in it as well, specifically I've moved several of the attached behaviors into the new Blend model.  Originally in my local version I did it to the JulMar.Wpf.Helpers.dll and got a dependency against System.Windows.Interactivity.dll.

I decided that for this release I didn't want to force that dependency so I created a secondary assembly JulMar.Wpf.Behaviors.dll which has all those behaviors in it.  The breaking change is I removed the original attached behaviors from the library (DoubleClickBehavior, NumericTextBehavior, MouseDragBehavior) in favor of using these new versions.  I did update the sample to show how they get used.

In a recent Essential WPF class, one of the students wanted an ObservableDictionary which we whipped up there - I cleaned up that implementation somewhat and added it into this library along with some unit tests for it.

Again, please check the readme included in the .zip file -- as always you are free to do whatever you like with this code.  If you do anything interesting or fun, let me know!

 

Tuesday, August 04, 2009 1:14:38 PM (Central Daylight Time, UTC-05:00)  #    Comments [3] -
.NET | WPF | MVVM
# Monday, August 03, 2009

A recent series of blog entries at http://themechanicalbride.blogspot.com/ introduced the Rx framework (System.Reactive.dll) which is an assembly used in the Silverlight toolkit for UI testing purposes.  It essentially provides a mechanism to do event driven programming through LINQ.  I'll refer you to the blog referenced above for all the gory details - frankly I'm still trying to wrap my mind around it!

Silverlight isn't my favorite technology however, I much prefer working in WPF and so I spent some time rebuilding Rx for the desktop CLR!  My original approach was to take my favorite exploration tool, reflector (available for free from www.redgate.com), and disassemble all the classes into C#, placing them into a project file.  I found however that Reflector choked on some of the more complicated structures - requiring me to go and hand-edit a bunch of the code.  I realized while I was doing this that there was a much easier way to convert a Silverlight assembly to a WPF assembly.

As you probably already know, Silverlight shares the same assembly format as the desktop CLR - there is no difference in the IL or structure of the assembly itself.  The difference is in the dependency on mscorlib and other references.  Specifically, when you add an assembly via VS2008, it looks at the version of the referenced mscorlib to determine whether it's a desktop CLR assembly or Silverlight assembly. 

Here's the header of a Silverlight assembly examined through ILDASM:

// Metadata version: v2.0.50727
.assembly extern mscorlib
{
   .publickeytoken = (7C EC 85 D7 BE A7 79 8E ) // |.....y.
   .ver 2:0:5:0
}

Here is a desktop assembly:

// Metadata version: v2.0.50727
.assembly extern mscorlib
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .z\V.4..
  .ver 2:0:0:0
}

Notice the version difference .. Silverlight uses 2.0.5.0 of mscorlib and the desktop CLR uses 2.0.0.0.  The public key is also different, but this is really just used for loading purposes.

Assuming the assembly doesn't use something Silverlight specific, we can modify the assembly references and allow the asembly to be used in the desktop CLR fairly easily. 

Here's how I did it for System.Reactive.dll:

ILDASM System.Reactive.dll /out:SR.il

change the assembly references in the resulting IL text file (for mscorlib, system and system.core)

ILASM SR.il /resource=sr.res /output=WPF/System.Reactive.dll

That gave me a desktop version of the assembly without modifying anything in the code itself - much easier than my original reflector route!

Next, I took a couple of the samples from the blog and ported them to WPF - specifically, I took the events sample listed here http://themechanicalbride.blogspot.com/2009/07/developing-with-rx-part-1-extension.html and ported it to WPF to test it.  I made very few changes, primarily just switching Application.Current.MainWindow for Application.Current.RootVisual.  Here is the resulting project and switched assembly for anyone who is interested in it.

ExtensionEvents.zip (44.62 KB)

I think Rx is a fascinating piece of code, although it will take me a bit of time to realize just what I can do with it I suspect.  I'm looking forward to building more with this using WPF now that's for sure!

Monday, August 03, 2009 10:56:03 AM (Central Daylight Time, UTC-05:00)  #    Comments [1] -
.NET | Code | WPF
I'm a WPF Disciple
Search
Categories
Archive
<January 2010>
SunMonTueWedThuFriSat
272829303112
3456789
10111213141516
17181920212223
24252627282930
31123456
About the author/Disclaimer

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2010
Mark Smith
Sign In
All Content © 2010, Mark Smith
DasBlog theme 'Business' created by Christoph De Baene (delarou)