... a journey through WPF, MVVM and .NET4 RSS 2.0
# Saturday, February 06, 2010

I cannot count how many times people have requested the source code to the ATAPI.NET or ITAPI3 projects.  My response has always been that I was unable to release it due to ownership issues (it was developed under contract for a client).  I am pleased to announce this morning that I have worked through those issues and have been granted permission to release the project in it’s entirety as source code on CodePlex!

Here’s their new homes:  http://atapi.codeplex.com/ and http://itapi3.codeplex.com

I’ll open up discussion board access there as well for Q&A.  If you would like to contribute to the project, shoot me an email and we’ll see about getting you access!

Saturday, February 06, 2010 11:56:38 AM (Central Standard Time, UTC-06:00)  #    Comments [1] -
.NET | Code | Tapi

I’ve published it to http://mvvmhelpers.codeplex.com/ where I’ll continue to maintain and add to it.  Get the latest release from there!

Saturday, February 06, 2010 9:20:51 AM (Central Standard Time, UTC-06:00)  #    Comments [0] -

# Friday, February 05, 2010

In the last post, I referred to the DragPositionBehavior in the JulMar MVVM library.  This behavior allows any UIElement to be dragged and repositioned using the mouse without requiring any code logic on your part.  It’s easy to apply – using the traditional Blend syntax (easiest done by dragging the behavior onto an element):

    <Interactivity:Interaction.Behaviors>

        <julmar:DragPositionBehavior />

    </Interactivity:Interaction.Behaviors>


This is the simplest way to use this, however it doesn’t work when the behavior is to be applied with a Style – in my example in the prior post, we need to drag around the ListBoxItem container, not just the content.  So I showed an alternative syntax to apply the same behavior:

    <ListBox.ItemContainerStyle>

        <Style TargetType="ListBoxItem">

            <Setter Property="julmar:DragPositionBehavior.IsEnabled" Value="True" />


Here, the behavior is being applied by setting the IsEnabled attached property onto the ListBoxItem.  Here’s the implementation for that:

public static DependencyProperty IsEnabledProperty =

    DependencyProperty.RegisterAttached("IsEnabled", typeof(bool),
        typeof(DragPositionBehavior),

        new FrameworkPropertyMetadata(false, OnIsEnabledChanged));

 

public static bool GetIsEnabled(DependencyObject uie)

{

    return (bool)uie.GetValue(IsEnabledProperty);

}

 

public static void SetIsEnabled(DependencyObject uie, bool value)

{

    uie.SetValue(IsEnabledProperty, value);

}


This is a boilerplate example of an attached property – nothing to see here.  The magic happens in the PropertyChange callback:

private static void OnIsEnabledChanged(DependencyObject dpo,

                                       DependencyPropertyChangedEventArgs e)

{

    UIElement uie = dpo as UIElement;

    if (uie != null)

    {

        var behColl = Interaction.GetBehaviors(uie);

        var existingBehavior = behColl.FirstOrDefault(b => b.GetType() ==
              typeof(DragPositionBehavior)) as DragPositionBehavior;

        if ((bool)e.NewValue == false && existingBehavior != null)

        {

            behColl.Remove(existingBehavior);

        }

        else if ((bool)e.NewValue == true && existingBehavior == null)

        {

            behColl.Add(new DragPositionBehavior());

        }

    }

}


Let’s break this down a little.  When we have the IsEnabled property set onto an element, first we verify it’s a UIElement (we cannot drag it on anything that isn’t because the mouse events are defined at this level).  Next, we check the behaviors collection on that element – if an existing behavior is there and we are setting the property to “false”, then we remove the existing behavior from the collection.  If there is no behavior, and we are setting the property to “true”, then we add a new DragPositionBehavior instance to the collection here.  This, in effect, is exactly what the first block of XAML is doing, and it’s what we do as well here in code – so the Style setter works as expected.

This isn’t really a trick – I’m sure others have thought of it as well, but it’s a useful thing to add into your behaviors so they can be universally used, both by Blend as well as by developers directly wanting to apply it in places where Blend cannot today.

Friday, February 05, 2010 5:01:51 PM (Central Standard Time, UTC-06:00)  #    Comments [2] -
.NET | MVVM | WPF

In this post, we will look at the IUIVisualizer, and bring together some of the concepts we’ve talked about already through a new sample – a simple picture viewer:

image

The application grabs all the images from the user’s photo folder and then displays each one onto the surface of a corkboard.  You can change the properties of an image, remove an image or add additional images.  It’s not designed to be a true image application ala photoSuru, it’s really more of a sample of MVVM practices with the helper library.  Here’s some of the coding examples present in the sample:

  • It registers a ISelectFile service and implements it as an OpenFileDialog.
  • It displays a “Picture Properties” dialog using the IUIVisualizer service.
  • It maps mouse DoubleClick on an image into a command in the ViewModel to display the properties.
  • It provides drag support through a behavior on the style.

Let’s look at this four features in particular.  Download the sample from here:

PictureViewer

Open the project in Visual Studio 2008 SP1, it should build and run without any issues.  The project structure is pretty much like all the other samples I’ve blogged about – I’m trying to keep to a consistent model:

image

Service Registration

If you look at the App.xaml.cs code behind, you’ll find the registration work being done in the constructor:

public App()

{

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

    ViewModel.RegisterKnownServiceTypes();

 

    // Register the file selector service.

    ViewModel.ServiceProvider.Add(typeof(ISelectFile), new OpenFileDialogSelector());

 

    // Register the UI dialogs.

    var uiVisualizer = ViewModel.ServiceProvider.Resolve<IUIVisualizer>();

        uiVisualizer.Register("ShowElementProperties", typeof(PropertyWindow));

}


First, note that it registers the standard services – that’s something I always do, even if I don’t anticipate needing them all, it doesn’t hurt to have them there. Next, it adds the file selector service by calling ServiceProvider.Add on the ViewModel class.  The interface is defined as a single method:

namespace PictureViewer.Interfaces

{

    public interface ISelectFile

    {

        string SelectFile(string fileFilters);

    }

}


The registration ties this interface to an implementation that displays the OpenFileDialog, for testing purposes, that would be replaced with a minimum of two implementations: one that returns null/empty and one that returns a valid filename to test both cases.

The final line in the app.xaml.cs file registers a UI dialog to display the properties of the image.  This is done through the IUIVisualizer interface which is defined in the helper library:

namespace JulMar.Windows.Interfaces

{

    public interface IUIVisualizer

    {

        void Register(string key, Type winType);

        bool Unregister(string key);

        bool Show(string key, object state, bool setOwner,

                  EventHandler<UICompletedEventArgs> completedProc);

        bool? ShowDialog(string key, object state);

    }

}


Notice the Register and Unregister methods take a string defined as a “key”.  This is the key that invokers will use to display the UI visually; I often use the typename of the View, but you can use any string here as long as you are consistent in registration vs. invocation.  In this sample, I’ve used the key “ShowElementProperties” – we’ll see in a moment how it is displayed.  The second parameter for the Register method takes the Type to display.  The type must be a WPF Window-derived type (i.e. NavigationWindow or Window) and will represent the View in our MVVM pattern.

Displaying a UI with IUIVisualizer

In the PictureViewModel type, there is an ICommand that is used to drive the Property window:

/// <summary>

/// Command to show the image properties.

/// </summary>

public ICommand ShowPropertiesCommand { get; private set; }


The default constructor fills that in with a DelegatingCommand to jump to a method of the ViewModel:

public PictureViewModel()

{

    _picture = new PictureInfo();

    ShowPropertiesCommand = new DelegatingCommand(ShowProperties);

    SelectNewImageFile = new DelegatingCommand(OnSelectNewFile);

    RemovePicture = new DelegatingCommand(

                  () => SendMessage(MainViewModel.RemovePictureMessage, this));

}

 

/// <summary>

/// Display the UI associated with this picture

/// </summary>

internal void ShowProperties()

{

    var uiVisualizer = Resolve<IUIVisualizer>();

    if (uiVisualizer != null)

    {

        uiVisualizer.ShowDialog("ShowElementProperties", this);

    }

}


The handler method is marked as internal because the MainViewModel forwards it’s own command to this same method handler (from the menu and toolbar).  Notice that the method first gets the IUIVisualizer service; you must use the same service instance where you registered the UI view.  Next, it calls ShowDialog to display a modal view.  It takes two parameters – the view key, and the view model.

A modal view is one that forces the user to interact and dismiss the dialog before they can continue working with the other elements in the application.  It is what, as an example, applications often use for Options dialogs.  ShowDialog will display the View associated with the given string key (“ShowElementProperties”).  The second parameter is the ViewModel you want to associate to it – in this case we are passing the associated picture we want to work with.  The dialog is then displayed and allows the user to edit the picture properties:

image

The XAML code for this view is contained in the PropertyWindow.xaml file – it has a couple of interesting elements to it which you will see when you interact with this dialog:

1. Watermarked Text display: if you remove the title, it will display some grayed out text in it’s place “Enter the Title Here”:

image

2. Numeric TextBox:  if you move your mouse cursor over the X/Y/Width/Height boxes you will see a sizing arrow that allows you to drag and change the values without typing.  You can also double-click to change the values and it enforces numeric text box behavior.

image

Both of these are accomplished with Blend Behaviors. There are plenty of resources on the web about these so I won’t go into detail on their creation – check the library source code if you want to see how they work, but using them involves taking a dependency on two assemblies:

  1. System.Windows.Interactivity.dll
  2. JulMar.Wpf.Behaviors.dll

Both of these are included in the Dependencies folder.  The first comes from the Blend SDK and is freely redistributable with your project.  To use them, you add the behavior to the visual element in question, for example, the watermarked textbox behavior gets applied like this:

<TextBox Text="{Binding Title}">

    <Interactivity:Interaction.Behaviors>

        <julmar:WatermarkTextBoxBehavior Text="Enter the Title Here"/>

    </Interactivity:Interaction.Behaviors>

    <TextBox.Style>

        <Style TargetType="TextBox" BasedOn="{StaticResource {x:Type TextBox}}">

            <Setter Property="FontStyle" Value="Normal" />

            <Style.Triggers>

                <Trigger Property="julmar:WatermarkTextBoxBehavior.IsWatermarked"

                        Value="True">

                    <Setter Property="FontStyle" Value="Italic" />

                    <Setter Property="Foreground" Value="LightGray" />

                </Trigger>

            </Style.Triggers>

        </Style>

    </TextBox.Style>

</TextBox>


I’ve also applied a Trigger to change the font/colors when the TextBox is watermarked.

The numeric behavior looks like this:

<TextBox Grid.Row="5" Text="{Binding Width, UpdateSourceTrigger=PropertyChanged}">

    <Interactivity:Interaction.Behaviors>

        <julmar:NumericTextBoxBehavior AllowMouseDrag="True" />

    </Interactivity:Interaction.Behaviors>

</TextBox>


Notice that I’ve changed the Binding.UpdateSourceTrigger to be PropertyChanged – this is so the dragging effect works properly and updates the value in the underlying view model.

Ways to invoke commands in the view

So let’s look now at how we get the command executed.  Switching to the MainWindow.xaml you will find three places where the Show Properties command is wired up.

First, it can be invoked using a keyboard accelerator. This requires using a BindableCommand from the library, placing it into resources and then binding against that.  The command we will be executing is the one on the MainViewModel so it requires the actual picture element as a parameter:

<Window.Resources>

    <julmar:BindableCommand x:Key="propsCommand" Command="{Binding ShowPropertiesCommand}"

                           CommandParameter="{Binding SelectedPicture}" />

</Window.Resources>

 

<Window.InputBindings>

    <KeyBinding Key="r" Modifiers="Ctrl+Alt" Command="{StaticResource propsCommand}" />

</Window.InputBindings>


The MainViewModel simply forwards this command onto the PictureViewModel using a typed DelegatingCommand:

ShowPropertiesCommand = new DelegatingCommand<PictureViewModel>(

                    p => p.ShowProperties(), p => p != null);


Next, we can invoke the command using the menu and toolbar:

    <MenuItem Header="_Edit">

        <MenuItem Header="Add _New Picture" Command="{Binding AddNewCommand}" />

        <MenuItem Header="_Remove Picture" Command="{Binding RemoveCommand}"

                  CommandParameter="{Binding SelectedPicture}" />

        <Separator />

        <MenuItem Header="P_roperties" Command="{Binding ShowPropertiesCommand}"

                  CommandParameter="{Binding SelectedPicture}" />

    </MenuItem>

 

   ...

 

<ToolBar DockPanel.Dock="Top">

        <Button ToolTip="Add New Picture" Command="{Binding AddNewCommand}"

                Content="+" FontWeight="Bold" />

        <Button ToolTip="Remove Picture" Command="{Binding RemoveCommand}"

            CommandParameter="{Binding SelectedPicture}" Content="-" FontWeight="Bold" />

        <Button ToolTip="Properties" Command="{Binding ShowPropertiesCommand}"

            CommandParameter="{Binding SelectedPicture}" />

   ...

 

Note that here we are also binding to the MainViewModel command – so we must supply the parameter using the CommandParameter.  The final invocation place is when you double-click on the picture itself.  This is done a little differently if you’ve not done much WPF work. 

A quick segway – View code behind vs. View Models

First, the display of images is actually housed in a ListBox.  It turns out that anytime you need to display multiple things grouped somehow, and allow the user to select one or more of those things, a ListBox is almost always the way to go.  WPF allows us to customize the visuals however we like, so here the panel has been replaced with a Canvas (allowing pixel positioning), and each item is drawn as a DataTemplate.  The template decides how to render each item in the ListBox – the PictureViewModel in this case.  In the sample, it is rendering an image and an optional TextBlock that is turned on and off through a property (and can be changed through the tool bar).  I encourage you to look at the code to see how all that is done. 

One of the core things necessary in MVVM is the ability to interact with visuals and then sometimes push notifications of that interaction back to the view model.  I say “sometimes” because it’s perfectly acceptable to place code into the code behind for the XAML as well. Where you put the logic depends on whether it is view-specific and whether you want to test it independently of the view.  If it’s not view specific OR you want to test it, then move it into the view model.  An example of something that we probably don’t care about is closing the application – I’ve wired it up to a command here just to show that you can, but it’s completely unnecessary to do that.  The view model isn’t doing any closing logic, so it would be fine to wire a handler into the MainWindow.xaml.cs and just call “this.Close()” in there.

Ok, so back to the double-click implementation.  In the DataTemplate assigned to the ListBox.ItemTemplate property you will find the definition for the image itself:

<Image x:Name="imageHolder" Width="{Binding Width}" Height="{Binding Height}"

      Source="{Binding Image}" Stretch="Fill"

       HorizontalAlignment="Center" VerticalAlignment="Center">

    <Interactivity:Interaction.Triggers>

        <julmar:DoubleClickTrigger>

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

        </julmar:DoubleClickTrigger>

    </Interactivity:Interaction.Triggers>

</Image>


Note the use of the Interaction.Triggers tag – this is also part of the Blend behavior implementation.  In this case, we are triggering off something (property change, event, etc.) and then performance some action.  In the JulMar.Wpf.Behaviors assembly you will find a whole bunch of triggers, behaviors and actions.  In this case, I am using the DoubleClickTrigger which monitors for a quick double tap of the left mouse button.  When that happens, it runs the list of actions associated with it – in this case, it invokes the ShowPropertiesCommand.  Now, here we are defining the trigger behavior on the UI that is bound to an actual PictureViewModel (note the property bindings on the image and you will see that I’m telling you the truth!) So here the command being invoked is the PictureViewModel command – so no parameter is necessary.

Drag/Position Behavior

The last thing I want to point out is the dragging behavior.  This is also done through a Blend behavior, but it is being applied in a slightly different way: through a Style. 

<ListBox.ItemContainerStyle>

    <Style TargetType="ListBoxItem">

        <Setter Property="julmar:DragPositionBehavior.IsEnabled" Value="True" />

        <Setter Property="Canvas.Left" Value="{Binding X, Mode=TwoWay}" />

        <Setter Property="Canvas.Top" Value="{Binding Y, Mode=TwoWay}" />

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

...

Now, for those who have used Blend behaviors a lot, you may now that it is currently not possible to apply behaviors through Styles.  This is a restriction of the Attached Property definition being used – the collection cannot be associated on a style.  This is a very unfortunate problem because it makes my scenario very hard: I want to drag and reposition these items around through the mouse.  If I put the behavior onto the DataTemplate then I move the content but not the item container itself (the thing that provides selection and focus rendering)  So I would end up with a very weird visualization where you click on an item and the focus rectangle is drawn in a completely different place than the item itself!

So, in my set of behaviors, many of them allow you to setup the behavior both through Blend and through Style setters (or directly on an element without the full Blend syntax).  I do this by adding an attached property onto the behavior class and then injecting my behavior into the element where the attached property is set.  I’ll show this in a future blog post to give an example for those who’d like to do the same for their own behaviors.

Another question I’ve fielded is why did I even create this behavior at all when the Blend sample already exists to do this?  Well, the short answer is because I had a specific goal in mind here – this behavior knows about Canvas panels.  If the behavior is attached to an element in a Canvas, it changes the position by changing the Canvas.Left and Canvas.Top properties.  If not, it uses a RenderTransform.  The supplied blend sample only uses RenderTransform (at least when I last looked at it).

That about covers it, if you have any questions or comments, then contact me!

Friday, February 05, 2010 4:43:16 PM (Central Standard Time, UTC-06:00)  #    Comments [0] -
.NET | MVVM | WPF
# Monday, February 01, 2010

In this post, I will go over the simple message visualizers available in the MVVM Helpers toolkit.  Essentially the idea is that it is fairly common to want to display a simple message from the ViewModel to the user.  Since the VM is supposed to be testable, we encapsulate this ability into four services, three of which I’ll focus on here:

IMessageVisualizer Displays a title + message to the user and allows them to dismiss it through a set of user-defined buttons.  The button used to dismiss the dialog is returned as the result.
IErrorVisualizer Displays a title + message to the user to report an error.  The only button displayed is OK, and the visualizer returns true/false.
INotificationVisualizer Used to manage some short operation that will halt the UI briefly.
IUIVisualizer Displays a custom modal or modaless UI to the user with an associated ViewModel to drive it.


To demonstrate the first three visualizer types, we’ll build a very simple MVVM application to display messages.  I start with the project template and remove all the ViewModel and View code to have a blank solution.  Each of the three visualizers we are going to look at take a string Title and Message as their parameters – we’ll drive it from a unique command for each.  To start with, let’s define a simple data structure that wraps an ICommand and a textual title:

/// <summary>

/// Simple command + title text

/// </summary>

public class TitledCommand

{

    /// <summary>

    /// Title to display

    /// </summary>

    public string Title { get; private set; }

 

    /// <summary>

    /// Command to execute

    /// </summary>

    public ICommand Command { get; private set; }

 

    /// <summary>

    /// Constructor

    /// </summary>

    /// <param name="title"></param>

    /// <param name="cmd"></param>

    public TitledCommand(string title, ICommand cmd)

    {

        Title = title;

        Command = cmd;

    }

}


Next, in the MainViewModel.cs file, we need a Title string property – this will be the title for each of the visualziations.  It’s just a simple field-backed INPC property, we’ll bind it to something in the view:

/// <summary>

/// Main View Model

/// </summary>

public class MainViewModel : ViewModel

{

    private string _title;

 

    /// <summary>

    /// Title for visualizations

    /// </summary>

    public string Title

    {

        get { return _title; }

        set { _title = value; OnPropertyChanged("Title"); }

    }

 

}


Now we can create a collection of the TitledCommand objects and display them to the user for execution.  We will place this collection into the MainViewModel.cs.  Let’s populate it with a set of delegating commands for each type of visualization we want to create.  We will use the DelegatingCommand<T> version which allows us to type the parameter being passed.  We will assume the inbound parameter is always the message to display and there a string:

/// <summary>

/// Main View Model

/// </summary>

public class MainViewModel : ViewModel

{

    ...

    /// <summary>

    /// Visualization Command list

    /// </summary>

    public IList<TitledCommand> VisualizationCommands { get; private set; }

 

    /// <summary>

    /// Constructor

    /// </summary>

    public MainViewModel()

    {

        VisualizationCommands = new List<TitledCommand>

        {

            new TitledCommand("Show Message", new DelegatingCommand<string>(OnShowMessage,

                s => !string.IsNullOrEmpty(Title) && !string.IsNullOrEmpty(s))),

            new TitledCommand("Show Error", new DelegatingCommand<string>(OnShowError,

                s => !string.IsNullOrEmpty(Title) && !string.IsNullOrEmpty(s))),       

            new TitledCommand("Show Notification",

                new DelegatingCommand<string>(OnShowNotification,

                s => !string.IsNullOrEmpty(Title))),

        };

    }

}


The CanExecute handler for each of them will test the Title property – ensure there is a value there, and the inbound parameter (the Message) and make sure there is a value there as well.

IMessageVisualizer

The IMessageVisualizer is used to show a simple message to the user – it takes a title, message and an enumeration to decide which buttons to display.  The default implementation of the service displays a MessageBox.  

image

The buttons you can display include:

    public enum MessageButtons

    {

        OK = 0,

        OKCancel = 1,

        YesNoCancel = 3,

        YesNo = 4

    }


The result from the service is which button was used to dismiss the dialog:

    public enum MessageResult

    {

        None = 0,

        OK = 1,

        Cancel = 2,

        Yes = 6,

        No = 7

    }


Using the visualizer is very easy – request the service from the service locator using the Resolve method (this requires you derive from the JulMar.Windows.Mvvm.ViewModel base class, or hit the service locator using the static property):

    private void OnShowMessage(string message)

    {

        var messageVisualizer = Resolve<IMessageVisualizer>();

        if (messageVisualizer != null)

        {

            Result = Enum.GetName(typeof (MessageResult),

               messageVisualizer.Show(Title, message, MessageButtons.YesNoCancel));

        }

    }


Notice that I test to ensure the visualizer is available – remember that services can be replaced or removed – I might do this in my unit tests for example (I actually mock the interface rather than replace it, but you get the point – test to make sure it’s there).

We want to see the result, so I take the resulting enum and convert it to a string and assign it to a new Result property on the ViewModel.  This, like Title, is just a field-backed string that does a property change notification.

IErrorVisualizer

The error visualizer is for cases where you want to display an error dialog to the user with a title and message.  The default implementation displays a MessageBox with an OK button

image

It returns a boolean response indicating that the user clicked the OK button (versus dismissing using the Close “X” button).   It has a similar interface to the message visualizer:

    private void OnShowError(string errorMessage)

    {

        var errorVisualizer = Resolve<IErrorVisualizer>();

        if (errorVisualizer != null)

        {

            Result = errorVisualizer.Show(Title, errorMessage).ToString();

        }

    }


We will assign the boolean result to the string Result property as well.

INotificationVisualizer

This visualizer is for cases where you are doing something in the ViewModel logic, on the UI thread that takes a moment to process.  Sorting a list, or searching an in-memory list might be an example.  True long-running operations should always be on a separate thread and use properties or the message mediator to coordinate with the UI thread.  That said, there are times when you want to do the logic inline with the request and you know it’s going to take a second or two to process it.  Enter the INotificationVisualizer.  It takes the same title and message as it’s cousin visualizers but the default implementation does not use them – instead, the default implementation simply changes the cursor to an hourglass (the defacto standard for “please wait”).  This is a service that I often replace with a custom visualzation – a progress bar, thumbar progress on Windows 7, or even a dialog overlay.  Invoking it is simple:

    private void OnShowNotification(string message)

    {

        var notifyVisual = Resolve<INotificationVisualizer>();

        if (notifyVisual != null)

        {

            using (notifyVisual.BeginWait(Title, message))

            {

                // Sleep for 2sec, pretending to work

                Thread.Sleep(2000);

            }

        }

    }


The BeginWait() method kicks off the notification visual (hourglass cursor in this case).  It returns a disposable object that you invoke Dispose on to return to the normal cursor.  Again, let me stress this is not optimal for a true long-running operation – this locks the UI up until the thread returns so only use this for very short operations.

Creating the View

The View for this application will be simple – let’s use an ItemsControl to generate a button for each of the exposed commands, two TextBoxes to hold the Title and Message, and then a TextBlock for the result, here’s what I want it to look like:

image

I’ll let you go through the XAML – it’s straightforward and should be pretty easy to follow.  The only new thing might be that we’ll set focus to the first focusable element using the FirstFocusedElement markup extension:

<Window x:Class="ServicesTest.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:ServicesTest.ViewModels"

   Title="Notification Visualizer Test" Height="300" Width="400" Background="LightYellow"

   WindowStartupLocation="CenterScreen"

   FocusManager.FocusedElement="{julmar:FirstFocusedElement}"

   DataContext="{julmar:ViewModelCreator {x:Type ViewModels:MainViewModel}}">

    <Grid Margin="5">

        <Grid.RowDefinitions>

            <RowDefinition Height="Auto" />

            <RowDefinition Height="Auto" />

            <RowDefinition Height="Auto" />

            <RowDefinition />

        </Grid.RowDefinitions>

 

        <Grid.ColumnDefinitions>

            <ColumnDefinition Width="Auto" />

            <ColumnDefinition />

        </Grid.ColumnDefinitions>

 

        <Label Grid.Column="0" Grid.Row="0" Content="Title:" />

        <TextBox Grid.Column="1" Grid.Row="0" Margin="5,2" Text="{Binding Title}" />

 

        <Label Grid.Column="0" Grid.Row="1" Content="Message:" />

        <TextBox x:Name="tbMessage" Grid.Column="1" Grid.Row="1" Margin="5,2" />

 

        <ItemsControl Grid.Row="2" Grid.ColumnSpan="2" Margin="10"

                    ItemsSource="{Binding VisualizationCommands}">

            <ItemsControl.ItemTemplate>

                <DataTemplate>

                    <Button Margin="5" Content="{Binding Title}"

                       Command="{Binding Command}"

                       CommandParameter="{Binding ElementName=tbMessage, Path=Text}" />

                </DataTemplate>

            </ItemsControl.ItemTemplate>

        </ItemsControl>

 

        <TextBlock FontSize="24pt" Grid.ColumnSpan="2" Grid.Row="3"

              HorizontalAlignment="Center" VerticalAlignment="Center"

              Text="{Binding Result, FallbackValue=None}" />

 

    </Grid>

</Window>


That should do it – if you’d like to just download the project and play with it, it’s available here: VisualizerTest.zip.  In the next post we’ll take a look at the grand-daddy of the message visualizers in the MVVM Helper toolkit: the IUIVisualizer!

Monday, February 01, 2010 9:59:35 AM (Central Standard Time, UTC-06:00)  #    Comments [0] -
.NET | MVVM | WPF
# Friday, January 29, 2010

A question I got recently was how to manage Radio Buttons with bindings – in this instance, the sample code was trying to map a single value to a set of Radio Buttons based on an enumeration set.  The original implementation was using a Value Converter to compare the “bound” value with the enumeration value expected for that radio button choice – if it was equal then the converter returned true, otherwise false.  Something like this:

<RadioButton Content="Blue"

     IsChecked="{Binding SelectedValue,

             Converter={StaticResource CheckValueAgainst}, ConverterParameter=Blue"/>

<RadioButton Content="Red"

     IsChecked="{Binding SelectedValue,

             Converter={StaticResource CheckValueAgainst}, ConverterParameter=Red"/>

<RadioButton Content="Yellow"

     IsChecked="{Binding SelectedValue,

             Converter={StaticResource CheckValueAgainst}, ConverterParameter=Yellow"/>


Initially this seemed to work, but as you changed the current enumeration value, the radio buttons would “lose” the binding – and after a few times you would end up with none of them selected.

Ultimately, this problem is really an expected behavior from WPF – when a set of Radio Buttons are placed together, they act as a group – where only one is expected to be checked and all the others are unchecked.  This happens because the selected Radio Button itself tells the group to uncheck all the others.  This has the effect of replacing the binding value for IsChecked with a local value of false.  See the problem?  Eventually, all of the buttons in the group have their value replaced and so we end up with all of them unchecked.  The solution was very easy – put each one into a separate group by defining a unique GroupName for each Radio Button. 

<RadioButton GroupName="gBlue" Content="Blue"

     IsChecked="{Binding SelectedValue,

             Converter={StaticResource CheckValueAgainst}, ConverterParameter=Blue"/>

<RadioButton GroupName="gRed" Content="Red"

     IsChecked="{Binding SelectedValue,

             Converter={StaticResource CheckValueAgainst}, ConverterParameter=Red"/>

<RadioButton GroupName="gYellow" Content="Yellow"

     IsChecked="{Binding SelectedValue,

             Converter={StaticResource CheckValueAgainst}, ConverterParameter=Yellow"/>


This solves the problem and required no real code changes, but of course, I didn’t want to stop there – I just had to whip up a quick MVVM version to show how I’d do this if I were responsible for the application!

Sample Application Description

Our goal will be to display a list of children and their details to track their favorite games.  I started by sketching it out with SketchFlow to get a sense of what I wanted to visually create:

image

The top list is a ListBox, showing each child and the bottom pane shows the details.  Note the RadioButtons used to represent Gender and Favorite Game.  Our goal will be to use a ListBox there as well – showing the list of Radio Buttons and bound to a ViewModel collection of data.  As a secondary goal, we want to separate the RadioButton value from the text displayed

It turns out that anytime you need to display a list or sequence of something, a ListBox (or ItemsControl if you don’t need the selection capability) is almost always a good choice.  Let’s see if we can make it work here with the MVVM pattern.

Now that I have an idea of what I want to build, I created a blank Windows WPF application and added the JulMar MVVM Helper library and created the directory structure I prefer (Views, ViewModels and Dependencies).  I moved the Window1.xaml and corresponding code behind into the Views folder and renamed it MainWindow.xaml.  This also required I adjust App.xaml to point to the correct StartupUri (Views\MainWindow.xaml).  As a quick start you could also just use the JulMar MVVM project template and delete the XAML and view models.  Here’s what I ended up with in the solution:

GamePrefSolution

Now, we’re ready to begin our data modeling.  In this case, I don’t have a real data model – I’m not going to store or manage any of the children in a persistent way so I’m just going to define the View Model definitions for the children and collection.  We’ll start with the child definition.  I created a class to manage the properties of the child I want to display: Name, Dob, Gender, and FavoriteGame.  For the Gender and Favorite Game, I will use Enums to model those as a known list.  I could have used a Boolean for Gender as well, but this serves my underlying goal so we’ll go with an enumeration.  Here’s what I came up with:

/// <summary>

/// Gender flag

/// </summary>

public enum Gender

{

    Male, Female, Unknown

}

 

/// <summary>

/// Game types

/// </summary>

public enum GameType

{

    Webkinz,

    Playdoh,

    PbsKids,

    Wii

}

 

/// <summary>

/// ViewModel to represent a single child.

/// </summary>

public class ChildViewModel : SimpleViewModel

{

    private string _name;

    private Gender _gender;

    private DateTime _dob;

    private GameType _favoriteGame;

 

    /// <summary>

    /// Name

    /// </summary>

    public string Name

    {

        get { return _name; }

        set { _name = value; OnPropertyChanged("Name","Details"); }

    }

 

    /// <summary>

    /// Gender of child

    /// </summary>

    public Gender Gender

    {

        get { return _gender; }

        set { _gender = value; OnPropertyChanged("Gender","Details"); }

    }

 

    /// <summary>

    /// Date of birth

    /// </summary>

    public DateTime Dob

    {

        get { return _dob; }

        set { _dob = value; OnPropertyChanged("Dob","Details"); }

    }

 

    /// <summary>

    /// Game they like to play

    /// </summary>

    public GameType FavoriteGame

    {

        get { return _favoriteGame; }

        set { _favoriteGame = value; OnPropertyChanged("FavoriteGame","Details"); }

    }

 

    /// <summary>

    /// Returns textual representation of child.

    /// </summary>

    /// <returns></returns>

    public string Details

    {

       get

       {

           return string.Format("{0} is a {1}, was born on {2:D} and loves to play {3}",

                        Name, Gender, Dob, FavoriteGame);

       }

    }

}


Pretty standard stuff – we have field backed properties and raise the PropertyChange notification on each one.  For this case I don’t think we’ll need any additional services so I derive from the JulMar.Windows.Mvvm.SimpleViewModel class which just provides INotifyPropertyChanged support.  The one extra thing I’ve added here is a Details property which is a concatenation of all the other properties – we’ll use this to verify that the data binding is working properly as a secondary display of the same data.  We need to be sure to include that property invalidation when any of the other properties it depends on changes.  The OnPropertyChanged implementation allows you to pass multiple strings for this very purpose.

Moving on, I want to display the generated Enumerations above as a list, so we need a way to encapsulate a value and the text used to represent the value together.  If I were using .NET4 I could use the uber-cool new Tuple<K,V> class but I want to target .NET 3.5 here so we’ll define a new ValueAndText class to hold this:

/// <summary>

/// This class wraps a value and string together.

/// </summary>

/// <typeparam name="T">Type of value</typeparam>

public class ValueAndText<T>

{

    /// <summary>

    /// Value to bind to

    /// </summary>

    public T Value { get; private set; }

 

    /// <summary>

    /// Text string to present

    /// </summary>

    public string Text { get; private set; }

 

    /// <summary>

    /// Constructor

    /// </summary>

    /// <param name="value"></param>

    /// <param name="text"></param>

    public ValueAndText(T value, string text)

    {

        Value = value;

        Text = text;

    }

}


Now, let’s turn to the actual glue – the MainViewModel that pulls it all together. 

/// <summary>

/// Main View Model that connects it all together.

/// </summary>

public class MainViewModel : SimpleViewModel

{

}

 

Let’s use a SimpleViewModel here as well.  The first property we need is a collection for the children – we won’t be modifying the list (i.e. no adding or deleting) so the backing storage can just be a List<T>, as part of the constructor we’ll populate it with some sample data:

/// <summary>

/// Collection of children

/// </summary>

public IList<ChildViewModel> Children { get; private set; }

       

/// <summary>

/// Constructor

/// </summary>

public MainViewModel()

{

   // Fill with sample data.

   Children = new List<ChildViewModel>

   {

      new ChildViewModel

      {

         Name = "Jonathan",

         Dob = new DateTime(2006, 3, 14),

         FavoriteGame = GameType.PbsKids,

         Gender = Gender.Male

      },

      ...

  };

}

  

Next, we want a single child to be the “current” selected child.  This is just a property of type ChildViewModel exposed by the parent view model.

private ChildViewModel _currentChild;

 

/// <summary>

/// The current (and only for now) child

/// </summary>

public ChildViewModel CurrentChild

{

   get { return _currentChild; }

   set

   {

      if (_currentChild != value)

      {

         _currentChild = value;

         OnPropertyChanged("CurrentChild");

      }

   }

}


We’ll also set the first child as the current child in the MainViewModel constructor after we populate the collection:

// Set the first child as selected.

CurrentChild = Children[0];


We want to have a bindable list of the gender values (and text) and a bindable list of the game types.  In this case, let’s take advantage of the ability to bind to any IEnumerable data source and just generate the list using the C# 2.0 iterator support:

/// <summary>

/// Gets the gender values

/// </summary>

public IEnumerable<ValueAndText<Gender>> GenderValues

{

    get

    {

        yield return new ValueAndText<Gender>(Gender.Male, "Boy");

        yield return new ValueAndText<Gender>(Gender.Female, "Girl");

    }

}

 

/// <summary>

/// Gets the game types

/// </summary>

public IEnumerable<ValueAndText<GameType>> GameTypes

{

    get

    {

        yield return new ValueAndText<GameType>(GameType.Webkinz,

                                             "WebKinz (http://www.webkinz.com)");

        yield return new ValueAndText<GameType>(GameType.Playdoh, "Loves Playdoh");

        yield return new ValueAndText<GameType>(GameType.PbsKids,

                                             "PBS Kids (http://www.pbskids.com)");

        yield return new ValueAndText<GameType>(GameType.Wii, "Wii and other console");

    }

}


That should do it for our logic and data requirements, now let’s turn to the visualization for it.  We have the following properties defined on the MainViewModel to drive the view:

Children Collection of PersonViewModel objects with child details.
CurrentChild Current (selected) child
GenderValues Collection of ValueAndText objects to select child gender
GameTypes Collection of ValueAndText objects to select the favorite game



Using the SketchFlow prototype as an example, we’ll start with a DockPanel as the root element – locking a StatusBar at the bottom, a ListBox at the top and a Border (which will contain our details pane) as the fill content.  We’ll use the JulMar ViewModelCreator markup extension to tie this to the MainViewModel, and let’s push the initial focus into the children ListBox using the FocusManager.FocusedElement attached property on the window.

<Window x:Class="RadioButtonBinding.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:RadioButtonBinding.ViewModels"

   xmlns:Controls="clr-namespace:Microsoft.Windows.Controls;assembly=WPFToolkit"

   DataContext="{julmar:ViewModelCreator {x:Type ViewModels:MainViewModel}}"

   FocusManager.FocusedElement="{Binding ElementName=lbChildren}"

   Title="Game Preference Tracker" Height="400" Width="500" Background="OldLace">

 

    <DockPanel>

 

        <!-- List of children we are tracking -->

        <ListBox x:Name="lbChildren" DockPanel.Dock="Top">

        </ListBox>

 

        <!-- StatusBar just to make sure two-way binding is working properly -->

        <StatusBar DockPanel.Dock="Bottom" BorderBrush="Black" BorderThickness="0,1,0,0">

        </StatusBar>

 

        <!-- Details pane -->

        <Border Margin="5" BorderBrush="LightGray" BorderThickness="1">

        </Border>

    </DockPanel>

</Window>


Next, let’s fill in the top ListBox details.  We need to populate it with the list of children – this is the Children property off our ViewModel, so we’ll bind the ItemsSource property to that collection.  Next, we’ll set the SelectedItem to the CurrentChild property – making sure to use a two-way binding:

<ListBox x:Name="lbChildren" DockPanel.Dock="Top" ItemsSource="{Binding Children}"

                SelectedItem="{Binding CurrentChild, Mode=TwoWay}" />


This will generate a list of items, but won’t have any decent visualization – so we’ll use a DataTemplate to give us a basic visual, at the same time, let’s replace the default panel with a WrapPanel so it looks more like our SketchFlow:

<ListBox x:Name="lbChildren" DockPanel.Dock="Top" ItemsSource="{Binding Children}"

        SelectedItem="{Binding CurrentChild, Mode=TwoWay}"

        ScrollViewer.HorizontalScrollBarVisibility="Disabled">

    <ListBox.ItemsPanel>

        <ItemsPanelTemplate>

            <WrapPanel />

        </ItemsPanelTemplate>

    </ListBox.ItemsPanel>

    <ListBox.ItemTemplate>

        <DataTemplate>

            <Border BorderBrush="DarkBlue" BorderThickness="2"

                    Background="SkyBlue" CornerRadius="5">

                <StackPanel Margin="10">

                    <TextBlock FontWeight="Bold" FontSize="12pt" Text="{Binding Name}" />

                    <TextBlock Text="{Binding FavoriteGame}" />

                </StackPanel>

            </Border>

        </DataTemplate>

    </ListBox.ItemTemplate>

</ListBox>


Now, let’s turn our attention to displaying the current child details.  Remember the properties we created on the ChildViewModel:

Name Their name
Gender Their gender – Male/Female
Dob The date of birth
Details The string with all the details for this child.


So let’s first use the details – we can bind a TextBlock in the StatusBar to the CurrentChild.Details property to display the selected child details:

<!-- StatusBar just to make sure two-way binding is working properly -->

<StatusBar DockPanel.Dock="Bottom" BorderBrush="Black" BorderThickness="0,1,0,0">

    <TextBlock Text="{Binding CurrentChild.Details}" TextWrapping="Wrap" />

</StatusBar>


Now, let’s turn our attention to the details – we’ll use a Grid to lay it out within the Border, the Name and Date Of Birth are pretty easy to just drop in a set of Labels and TextBox/DatePicker – we’ll need the WPF Toolkit for this.  We’ll drop in two ListBox elements for the Radio Button list.

<Border Margin="5" BorderBrush="LightGray" BorderThickness="1">

    <Grid>

        <Grid.Resources>

            <!-- Common style for header labels -->

            <Style TargetType="Label">

                <Setter Property="HorizontalAlignment" Value="Right" />

                <Setter Property="VerticalAlignment" Value="Top" />

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

                <Setter Property="Margin" Value="5,2" />

            </Style>

        </Grid.Resources>

 

        <Grid.ColumnDefinitions>

            <ColumnDefinition Width="Auto" />

            <ColumnDefinition />

        </Grid.ColumnDefinitions>

 

        <Grid.RowDefinitions>

            <RowDefinition Height="Auto" />

            <RowDefinition Height="Auto" />

            <RowDefinition Height="Auto" />

            <RowDefinition Height="Auto" />

        </Grid.RowDefinitions>

 

        <Label Grid.Row="0" Content="Name:" />

        <TextBox Grid.Row="0" Grid.Column="1" Margin="5,2"

             Text="{Binding CurrentChild.Name}" />

 

        <Label Grid.Row="1" Content="Gender:" />

        <ListBox Grid.Row="1" Grid.Column="1" />

 

        <Label Grid.Row="2" Content="Date Of Birth:" />

        <Controls:DatePicker Grid.Row="2" Grid.Column="1" Margin="5,2"

              SelectedDate="{Binding CurrentChild.Dob}" />

 

        <Label Grid.Row="3" Content="Favorite Game:" />

        <ListBox Grid.Row="3" Grid.Column="1" />

    </Grid>

</Border>


Let’s focus on the Gender list first – the same concepts will apply to the game list.  We have an IEnumerable list of ValueAndText objects – each object has a Value property (corresponding to the underlying enum value tracked in the ChildViewModel) and a Text property which is what we want displayed in the RadioButton choice.  First, let’s set it up so we get a list of RadioButtons – we can do this by changing the ControlTemplate for each item in the list itself – that is, change the ListBoxItem control template. 

As a bit of background, anytime you add an element to an ItemsControl (ListBox, ComboBox, TreeView, Menu, etc.) a special wrapper is internally created around your data to provide the special UI properties necessary to drive the functionality – things like focus, selection, mouse-over, etc. are all provided by this wrapper.  In the case of the ListBox, the created wrapper is a ListBoxItem class and we can control it’s properties by overriding the ItemContainerStyle on the ListBox itself.  So, to start off, we’ll create a new Style for the ListBox, set some basic properties and then override the ListBoxItem style inside that:

<Style x:Key="radioListBox" TargetType="ListBox"

       BasedOn="{StaticResource {x:Type ListBox}}">

    <Setter Property="BorderThickness" Value="0" />

    <Setter Property="Margin" Value="5" />

    <Setter Property="Background" Value="{x:Null}" />

    <Setter Property="ItemContainerStyle">

        <Setter.Value>

            <Style TargetType="ListBoxItem"

                   BasedOn="{StaticResource {x:Type ListBoxItem}}">

            </Style>

        </Setter.Value>

    </Setter>

</Style>


Since this is going to list a group of radio buttons, we’ll drop the border off the ListBox and the Background color as well so that our parent’s background shows through.  We’ll throw a Margin on there to give it a little spacing. Next, to change the visualization of the ListBoxItem, we’ll override it’s ControlTemplate (the thing that generates the visual tree for the item).  This, like all Controls in WPF, is done by overriding the Template property. What we want is put a Radio Button in there:

<Style TargetType="ListBoxItem" BasedOn="{StaticResource {x:Type ListBoxItem}}">

    <Setter Property="Template">

        <Setter.Value>

            <ControlTemplate TargetType="ListBoxItem">

               <RadioButton IsChecked="{TemplateBinding IsSelected}">

                  <ContentPresenter />

               </RadioButton>

            </ControlTemplate>

        </Setter.Value>

    </Setter>

</Style>


In order to get the IsChecked state properly setup, we’ll bind it to the ListBoxItem.IsSelected property – so if the item is selected according to the ListBox, then the Radio Button will be checked.  We also drop a ContentPresenter into the RadioButton so it displays whatever the data bound value is – this will provide for any DataTemplate visualization if one is present.  This will achieve the visualization we desire, but it won’t work properly as we interact with it.  The problem is that the Radio button will override this state when it is clicked – exactly the problem we had originally!

To fix this, let’s make the radio button invisible to the mouse and keyboard.. we can do this by setting the Focusable and IsHitTestable properties to false – however this makes them non-interactive and now we can’t select the ListBoxItem with the mouse.. so, let’s wrap it in something that is selectable – anything should work, so we’ll just throw it into a Grid.  Set the Grid.Background to transparent so you can click on it and we end up with:

<Style TargetType="ListBoxItem" BasedOn="{StaticResource {x:Type ListBoxItem}}">

    <Setter Property="Template">

        <Setter.Value>

            <ControlTemplate TargetType="ListBoxItem">

                <Grid Background="Transparent">

                    <RadioButton Focusable="False"

                      IsHitTestVisible="False" IsChecked="{TemplateBinding IsSelected}">

                        <ContentPresenter />

                    </RadioButton>

                </Grid>

            </ControlTemplate>

        </Setter.Value>

    </Setter>

</Style>


This does exactly what we want – clicking on the radio button changes the selection in the ListBox and, in turn, checks or unchecks the radio button in question.  Now, let’s wire it up to our data – remember we have a Value and Text.  We want to bind to the Value but display the Text.  It turns out the ListBox already has this feature backed in – there is a SelectedItem property we normally use, but there is also a SelectedValue property that makes the distinction between the item in the collection and the value used to select it.  There is also a DisplayMemberPath and SelectedValuePath property used for data binding purposes when generating the content from an ItemsSource supplied value.  Pulling these things together we can do this:

<ListBox Grid.Row="1" Grid.Column="1"

        Style="{StaticResource radioListBox}"

        DisplayMemberPath="Text"

        SelectedValuePath="Value"

        ItemsSource="{Binding GenderValues}"

        SelectedValue="{Binding CurrentChild.Gender}" />


Testing this, it works perfectly!  Since the DisplayMemberPath/SelectedValuePath are the same for the two lists, we can move that to our radioListBox style, leaving us with the two ListBox definitions being:

<ListBox Grid.Row="1" Grid.Column="1" Style="{StaticResource radioListBox}"

         ItemsSource="{Binding GenderValues}"

         SelectedValue="{Binding CurrentChild.Gender}" />

... 

<ListBox Grid.Row="3" Grid.Column="1" Style="{StaticResource radioListBox}"

         ItemsSource="{Binding GameTypes}"

         SelectedValue="{Binding CurrentChild.FavoriteGame}" />


And the completed application looks like:

image

You can download the completed project here: RadioButtonBinding Test

Friday, January 29, 2010 12:41:42 PM (Central Standard Time, UTC-06:00)  #    Comments [2] -
.NET | MVVM | WPF
# 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
I'm a WPF Disciple
Search
Categories
Archive
<March 2010>
SunMonTueWedThuFriSat
28123456
78910111213
14151617181920
21222324252627
28293031123
45678910
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)