Tuesday, February 09, 2010

Running code in a separate AppDomain

Suppose you’ve got a chunk of code that you need to run as part of your application but you’re concerned that it might bring down your app or introduce a memory leak.  Fortunately, the .NET runtime provides an easy mechanism to run arbitrary code in a separate AppDomain.  Not only can you isolate all exceptions to that AppDomain, but when the AppDomain unloads you can reclaim all the memory that was consumed.

Here’s a quick walkthrough that demonstrates creating an AppDomain and running some isolated code.

Create a new AppDomain

First we’ll create a new AppDomain based off the information of the currently running AppDomain.

AppDomainSetup currentSetup = AppDomain.CurrentDomain.SetupInformation;

var info = new AppDomainSetup()
              {
                  ApplicationBase = currentSetup.ApplicationBase,
                  LoaderOptimization = currentSetup.LoaderOptimization
              };

var domain = AppDomain.CreateDomain("Widget Domain", null, info);

Unwrap your MarshalByRefObject

Next we’ll create an object in that AppDomain and serialize a handle to it so that we can control the code in the remote AppDomain.  It’s important to make sure the object you’re creating inherits from MarshalByRefObject and is marked as serializable.  If you forget this step, the entire object will serialize over to the original AppDomain and you lose all isolation.

string assemblyName = "AppDomainExperiment";
string typeName = "AppDomainExperiment.MemoryEatingWidget";

IWidget widget = (IWidget)domain.CreateInstanceAndUnwrap(assemblyName, typeName);

Unload the domain

Once we’ve finished with the object, we can broom the entire AppDomain which frees up all resources attached to it.  In the example below, I’ve deliberately created a static reference to an object to prevent it from going out of scope.

AppDomain.Unload(domain);

Putting it all together

Here’s a sample that shows all the moving parts.

namespace AppDomainExperiment
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using Microsoft.VisualStudio.TestTools.UnitTesting;

    [Test]
    public class AppDomainLoadTests
    {
        [TestMethod]
        public void RunMarshalByRefObjectInSeparateAppDomain()
        {
            Console.WriteLine("Executing in AppDomain: {0}", AppDomain.CurrentDomain.Id);
            WriteMemory("Before creating the runner");

            using(var runner = new WidgetRunner("AppDomainExperiment",
                                                "AppDomainExperiment.MemoryEatingWidget"))
            {

                WriteMemory("After creating the runner");

                runner.Run(Console.Out);

                WriteMemory("After executing the runner");
            }

            WriteMemory("After disposing the runner");
        }

        private static void WriteMemory(string where)
        {
            GC.Collect();
            GC.WaitForPendingFinalizers();
            long memory = GC.GetTotalMemory(false);

            Console.WriteLine("Memory used '{0}': {1}", where, memory.ToString());
        }
    }

    public interface IWidget
    {
        void Run(TextWriter writer);
    }

    public class WidgetRunner
    {
        private readonly string _assemblyName;
        private readonly string _typeName;
        private AppDomain _domain;

        public WidgetRunner(string assemblyName, string typeName)
        {
            _assemblyName = assemblyName;
            _typeName = typeName;
        }

        #region IWidget Members

        public void Run(TextWriter writer)
        {
            AppDomainSetup currentSetup = AppDomain.CurrentDomain.SetupInformation;

            var info = new AppDomainSetup()
                          {
                              ApplicationBase = currentSetup.ApplicationBase,
                              LoaderOptimization = currentSetup.LoaderOptimization
                          };

            _domain = AppDomain.CreateDomain("Widget Domain", null, info);

            var widget = (IWidget)_domain.CreateInstanceAndUnwrap(_assemblyName, _typeName);

            if (!(widget is MarshalByRefObject))
            {
                throw new NotSupportedException("Widget must be MarshalBeRefObject");
            }
            widget.Run(writer);
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            GC.SuppressFinalize(this);
            AppDomain.Unload(_domain);
        }

        #endregion
    }

    [Serializable]
    public class MemoryEatingWidget : MarshalByRefObject, IWidgetModule
    {
        private IList<string> _memoryEater;

        private static IWidgetModule Instance;

        #region IAppLauncher Members

        public void Run(TextWriter writer)
        {
            writer.WriteLine("Executing in AppDomain: {0}", AppDomain.CurrentDomain.Id);

            _memoryEater = new List<string>();

            // create some really big strings
            for(int i = 0; i < 100; i++)
            {
                var s = new String('c', i*100000);
                _memoryEater.Add(s);
            }

            // THIS SHOULD PREVENT THE MEMORY FROM BEING GC'd
            Instance = this;
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            
        }

        #endregion
    }
}

Running the test shows the following output:

Executing in AppDomain: 2
Memory used 'Before creating the runner': 569060
Memory used 'After creating the runner': 487508
Executing in AppDomain: 3
Memory used 'After executing the runner': 990525340
Memory used 'After disposing the runner': 500340

Based on this output, the main take away is that the memory is reclaimed when the AppDomain is unloaded.  Why do the numbers not match up in the beginning and end?  It’s one of those mysteries of the managed garbage collector, it reminds me of my favorite Norm McDonald joke from SNL:

“Who are safer drivers? Men, or women?? Well, according to a new survey, 55% of adults feel that women are most responsible for minor fender-benders, while 78% blame men for most fatal crashes. Please note that the percentages in these pie graphs do not add up to 100% because the math was done by a woman. [Crowd groans.] For those of you hissing at that joke, it should be noted that that joke was written by a woman. So, now you don't know what the hell to do, do you? [Laughter] Nah, I'm just kidding, we don't hire women”

Happy Coding.

Submit this story to DotNetKicks

Monday, February 08, 2010

Twelve Days of Code – Wrap up

Well it’s been a very long twelve days indeed, and I accomplished more than I thought I would.  But alas, all good things must come to end, so after a short hiatus on the blog I’m back to close out the Twelve Days of Code series for 2009.

For your convenience, here’s a list of the posts:

I want to thank all those who showed interest in the concept and if there are folks out there who were following along at home, please drop me a line or a comment.

For those interested in seeing some of the .NET 4.0 code and extending my work, the code is available for download.

I may pick up the experiment again once the next release candidate for Visual Studio is released.

Submit this story to DotNetKicks

Tuesday, January 12, 2010

The Three Step Developer Flow

A long time ago, a mentor of mine passed on some good advise for developers that has stuck well with me: “Make it work.  Make it right.  Make it fast.”  While this simple mantra is likely influenced by Donald Knuth’s famous and misquoted statement that “premature optimization is the root of all evil, it’s more about how a developer should approach development altogether.

Breaking it down…

What I’ve always loved about this simple advice is that if a developer takes the steps out of order, such as putting emphasis on design or performance, there’s a very strong possibility that the code will never work.

Make it work…

Developers should take the most pragmatic solution possible to get the solution to work.  In some cases this should be considered prototype code that should be thrown away before going into production.  Sadly, I’m sure that 80% of all production code is prototype code with unrealized design.

Make it right…

Now that you know you know how to get the code to work, take some time to get into a shape that you can live with.  Interesting enough, emphasis should not be placed on designing for performance at this point.  If you can’t get to this stage, it should be considered technical debt to be resolved later.

Make it fast….

At this point you should have working code that looks clean and elegant, but how does it stack up when it’s integrated with production components or put under load?  If you had spent any time in the last two steps optimizing the code to handle load of a thousand users but it’s only called once in the application – you may have wasted your time and optimized prematurely.  To truly know, code should be examined under a profiler to determine if the code meets the performance goals of the application.  This is all a part of embedding a “culture of Performance” into your organization.

Aligned with Test Driven Development

It’s interesting that this concept overlaps with Test Driven Development’s mantra “Red, Green, Refactor” quite well.  Rather than developing prototype code as a console app, I write tests to prove that it works.  When it’s time to clean up the code and make it right, I’m refactoring both the tests and the code in small increments – after each change, I can verify that it still works. 

Later, if we identify performance issues with the code, I can use the tests as production assets to help me understand what the code needs to do.  This provides guidance when ripping out chunks of poorly performing code.

By following either the “red / green / refactor” or “make it work / right / fast" mantras mean that I don’t incorporate best practices or obvious implementation when writing the code? Hardly. I’ll write what I think needs to be written, but it’s important not to get carried away.

Write tests.  Test often.

Submit this story to DotNetKicks

Thursday, January 07, 2010

Twelve Days of Code – Unity Framework

As part of the twelve days of code, I’m building a Pomodoro style task tracking application and blogging about it. This post is the seventh in this series. This post focuses on using the Microsoft Unity Framework in our .NET 4.0 application.

This post assumes assumes that you are familiar with the last few posts and have a working understanding of Inversion of Control.  If you’re new to this series, please check out some of the previous posts and then come back.  If you’ve never worked with Inversion of Control, it’s primarily about decoupling objects from their implementation (Factory Pattern, Dependency Injection, Service Locator) – but the best place to start is probably here.

Overview

Our goal for this post is to remove as many hard-code references to types as possible.  Currently, the constructor of our MainWindow initializes all the dependencies of the Model and then manually sets the DataContext.  We need to pull this out of the constructor and decouple the binding from TaskApplicationViewModel to ITaskApplication.

Initializing the Container

We’ll introduce our inversion of control container in the Application’s OnStartup event.  The container’s job is to provide type location and object lifetime management for our objects, so all the hard-coded initialization logic in the MainWindow constructor is registered here.

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        IUnityContainer container = new UnityContainer();
        
        container.RegisterType<ITaskApplication, TaskApplicationViewModel>();
        container.RegisterType<ITaskSessionController, TaskSessionController>();
        container.RegisterType<IAlarmController, TaskAlarmController>();
        container.RegisterType<ISessionRepository, TaskSessionRepository>();

        Window window = new MainWindow();
        window.DataContext = container.Resolve<ITaskApplication>();
        window.Show();

        
        base.OnStartup(e);
    }
}

Also note, we’re initializing the MainWindow with our data context and then displaying the window.  This small change means that we must remove the MainWindow.xaml reference in the App.xaml (otherwise we’ll launch two windows).

Next Steps

Aside from the simplified object construction, it would appear that the above code doesn’t buy us much: we have roughly the same number of lines of code and we are simply delegating objection construction to Unity.  Alternatively, we could move the hard-coded registrations to a configuration file (though that’s not my preference here).

In the next post, we’ll see how using Prism’s Bootstrapper and Module configuration allows us to move this logic into their own modules.

In the next step, we’ll look at using P

Submit this story to DotNetKicks

Saturday, January 02, 2010

Twelve Days of Code – Entity Framework 4.0

As part of the twelve days of code, I’m building a Pomodoro style task tracking application and blogging about it. This post is the sixth in this series. Today I’ll be adding some persistence logic to the Pomodoro application.

I should point I’ve never been a huge fan of object-relational mapping tools, and while I’ve done a few tours with SQL Server I haven’t played much with SQLite.  I’ve heard good things about the upcoming version of the Entity Framework in .NET 4.0, so this post gives me a chance to play with both.

Getting Ready

As SQLite isn’t one of the default providers supported by Visual Studio 2010 (Beta 2), I downloaded and installed SQLite.  The installation adds the SQLite libraries to the Global Assembly Cache, and adds Designer Support for connecting to a SQLite database through the Server Explorer.  The installation and GAC’d assemblies may prove to be an issue later when we want to deploy the application, but we’ll worry about that later.

Creating a Session Repository

So far, the project structure has a “Core” and “Shell” project where the “Core” project contains the central interfaces for the application.  Since the ITaskSessionController already has the responsibility of handling starting and stopping of sessions, it is the ideal candidate to interact with a ISessionRepository for recording these activities against a persistent store.

To handle auditing of sessions, I created a ISessionRepository interface which lives in the Core library:

interface ISessionRepository
{
    void RecordCompletion(ITaskSession session);
    void RecordCancellation(ITaskSession session);
}

Although we don't have an implementation for this interface, we do know how that an object with this signature will be used by the TaskSessionController.  In anticipation of these changes, we add tests to the TaskSessionController that verify it communicates with its dependency:

public TaskSessionControllerSpecs : SpecFor<TaskSessionController>
{
  // ... initial context setup with Mock ISessionRepository
  // omitted for clarity

  public class when_a_session_completes : TaskSessionControllerSpecs
  {
     // omitted for clarity

     [TestMethod]
     public void ensure_activity_is_recorded_in_repository()
     {
         repositoryMock.Verify( 
            r => r.RecordCompletion(
                    It.Is<ITaskSession>( (s) => s == session )
                        );
     }
  }
}

To ensure the tests pass, we extend the TaskSessionController to take a ISessionRepository in its constructor and add the appropriate implementation.  Naturally, because the constructor of the TaskSessionController has changed, we adjust the fixture setup so that the code will compile.  Below is a snippet of modified TaskSessionController:

public class TaskSessionController : ITaskSessionController
{
    public TaskSessionController(ISessionRepository repository)
    {
        SessionRepository = repository;
    }

    protected ISessionRepository SessionRepository
    {
        get; set;
    }

    public void Finish(ITaskSession session)
    {
        session.Stop()

        SessionRepository.RecordCompletion(session);
    }

    // ...omitted for clarity
}

Adding ADO.NET Entity Framework to the Project

While we could add the implementation of the ISessionRepository into the Core library, I’m going to add a new library Pomodoro.Data where we’ll add the Entity Framework model.  This strategy allows us to extend the Core model and provides us with some freedom to create alternate persistence strategies simply by swapping out the Pomodoro.Data assembly.

Once the project is created, we add the Entity Framework to the project using the Add New “ADO.NET Entity Data Model” and follow the wizard:

Pomodoro.Data

Note, that the wizard adds the appropriate references to the project automatically. 

Since we don’t have a working database, we’ll choose to create an Empty Model.  Later on, we’ll generate the database from our defined model.

empty-model 

Creating a Data Model

One of the new features of the Entity Framework 4.0 is that it allows you to bind to an existing data model.  Although the TaskSession could be considered as a candidate for an existing model, it doesn’t fit the bill cleanly – Sessions represent countdown timers and they don’t track the final outcome.  Instead, we’ll use the default behavior of the framework and manually generate a model class, TaskSessionRecord:

add-new-entity

For our auditing purposes, we only need to record an ID, Start and End Times and whether the session was completed or cancelled.

task-session-record

Creating the Database from the Model

After the model is complete, we generate the database from the model:

  1. Right click the designer and choose “Model Browser”
  2. In the Data Store, choose “Generate Database from Model”
  3. Create a new database connection.  In our case, we specify SQLite provider
  4. Finish our the wizard by clicking Next and Finish.

new-database-connection

The wizard produces the Database and the matching DDL file to generate the tables.  Note that SQLite must be installed in order to have it appear as an option in the wizard.

Unfortunately, I wasn’t able to create the SQLite database using any of the tools with Visual Studio.  Instead, I cheated and manually created the TaskSessionRecord table.  We’ll hang onto the generated ddl file because we may want to programmatically generate the database at some point.  For the time being, I’ll cheat and copy the database to the bin\Debug folder.

Implementing the Repository

The repository implementation is fairly straightforward.  We simply instantiate the object context (we specified part of the name when we added the ADO.NET Entity Data Model to the project), add a new TaskSessionRecord to the EntitySet and then save the changes to commit the transaction:

namespace Pomodoro.Data
{
    public class TaskSessionRepository : ISessionRepository
    {
        public void RecordCompletion(ITaskSession session)
        {
            using (var context = new PomodoroDataContainer())
            {
                context.TaskSessionRecords.AddObject(new TaskSessionRecord(session, true));
                context.SaveChanges();
            }
        }

        public void RecordCancellation(ITaskSession session)
        {
            using (var context = new PomodoroDataContainer())
            {
                context.TaskSessionRecords.AddObject(new TaskSessionRecord(session, false));
                context.SaveChanges();
            }
        }
    }
}

Note that to simplify the code, I extended the auto generated TaskSessionRecord class to provide a convenience constructor.  Since the auto generated class is marked as partial, the convenience constructor is placed in its own file.  As some of the existing generated code requires the presence of an empty constructor (which is implicitly defined by the compiler if not present), we must also include a default constructor.

public partial class TaskSessionRecord
{
    // needed to satisfy some of the existing generated code
    public TaskSessionRecord()
    {
    }

    public TaskSessionRecord(ITaskSession session, bool complete)
    {
        Id = session.Id;
        StartTime = session.StartTime;
        EndTime = session.EndTime;
        Complete = complete;
    }
}

Integrating into the Shell

To integrate the new SessionRepository into the Pomodoro application we need to add the database, Pomodoro.Data assembly and the appropriate configuration settings.  For the time being, we’ll add a reference to Pomodoro.Data library to the Shell application – this strategy may change if we introduce a composite application pattern such as Prism or MEF.  For brevity sake, I’ll manually copy the database into the bin\Debug folder.

The connection string settings appear in the app.config like so:

<connectionStrings>
  <-- formatted for readibiliy -->
  <add name="PomodoroDataContainer" 
       connectionString="metadata=res://*/PomodoroData.csdl|res://*/PomodoroData.ssdl|res://*/PomodoroData.msl;
                    provider=System.Data.SQLite;
                    provider connection string=&quot;data source=Pomodoro.sqlite&quot;" 
       providerName="System.Data.EntityClient" />
</connectionStrings>

One Last Gotcha

As the solution is compiled against .NET Framework 4.0 and our Sqlite assemblies are compiled against .NET 2.0, we receive a really nasty error when the System.Data.SQLite assembly loads into the AppDomain:

Mixed mode assembly is built against version 'v2.0.50727' of the runtime and cannot be loaded in the 4.0 runtime without additional configuration information

We solve this problem by adding useLegacyV2RuntimeActivationPolicy="true" to the app.config:

<startup useLegacyV2RuntimeActivationPolicy="true">
  <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>

Next Steps

In the next post, we’ll look at adding Unity as a dependency injection container to the application.

Submit this story to DotNetKicks

Thursday, December 31, 2009

Twelve Days of Code – Windows 7 Shell Integration

As part of the twelve days of code, I’m building a Pomodoro style task tracking application and blogging about it. This post is the fifth in this series.  Today I’ll cover adding some of the cool new Windows 7 Shell integration features in WPF 4.0.

I’ll be revisiting some of the xaml and object model for this post, so it wouldn’t hurt to read up:

WPF 4.0 offers some nice Windows 7 Shell integration that are easy to add to your application.

Progress State

Since the Pomdoro application’s primary function is to provide a countdown timer, it’s seems like a natural fit to use the built-in Windows 7 Taskbar progress indicator to show the time remaining.  Hooking it up was a snap.  The progress indicator uses two values ProgressState and ProgressValue, where ProgressState indicates the progress mode (Error, Indeterminate, None, Normal, Paused) and ProgressValue is a numeric value between 0 and 1.  Two simple converters provide the translation between ViewModel and View, one to control ProgressState and the other to compute ProgressValue.

<Window.TaskbarItemInfo>
    <TaskbarItemInfo
        ProgressState="{Binding ActiveItem, Converter={StaticResource ProgressStateConverter}}"
        ProgressValue="{Binding ActiveItem, Converter={StaticResource ProgressValueConverter}}"
        >
    </TaskbarItemInfo>
</Window.TaskbarItemInfo>

Which looks something like this:

taskbar-progress

Note that for ProgressValue I’m binding to ActiveItem instead of TimeRemaining.  This is because the progress value is obtained through a percent complete calculation -- time remaining in the original session length – which requires that both values are available to the converter.  I suppose this could have been calculated through a multi-binding, but the single converter makes things much easier.

namespace Pomodoro.Shell.Converters
{
    [ValueConversion(typeof(ITaskSession), typeof(System.Windows.Shell.TaskbarItemProgressState))]
    public class ProgressStateConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value != null && value is ITaskSession)
            {
                ITaskSession session = (ITaskSession)value;

                if (session.IsActive)
                {
                    return TaskbarItemProgressState.Normal;
                }
            }
            return TaskbarItemProgressState.None;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }


    [ValueConversion(typeof(ITaskSession), typeof(double))]
    public class ProgressValueConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value != null && value is ITaskSession)
            {
                ITaskSession session = (ITaskSession)value;

                if (session.IsActive)
                {
                    int delta = session.SessionLength - session.TimeRemaining;
                    
                    return (double)(delta / (double)session.SessionLength);
                }
            }
            return 1;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

This is all well and good, but there’s a minor setback: Progress will not increment unless the PropertyChanged event is raised for the ActiveItem property.  This is an easy fix: the ITaskSession needs to expose a NotifyProgress event and the ITaskApplication needs to notify the View when the event fires.  Since the progress indicator in the taskbar is only a few dozen pixels wide, spamming the View with each millisecond update is a bit much.  We solve this problem by throttling the amount the event is raised using a NotifyInterval property.

// from TaskSessionViewModel
void OnTimer(object sender, ElapsedEventArgs e)
{
    NotifyProperty("TimeRemaining");

    if (IsActive)
    {
        // if notify interval is set
        if (NotifyInterval > 0)
        {
            notifyIntervalCounter += TimerInterval;

            if (notifyIntervalCounter >= NotifyInterval)
            {
                if (NotifyProgress != null)
                {
                    NotifyProgress(this, EventArgs.Empty);
                }
                notifyIntervalCounter = 0;
            }
        }
    }

    if (TimeRemaining == 0)
    {
        // end timer
        IsActive = false;

        if (SessionFinished != null)
        {
            SessionFinished(this, EventArgs.Empty);
        }
    }
}

TaskbarInfo Buttons

Using the exact same command bindings mentioned in my last post, adding buttons to control the countdown timer from the AreoPeek window is dirt simple. The only gotcha is that the taskbar buttons do not support custom content, instead you must specify an image to display anything meaningful to the user.

<Window ....>

    <Window.Resources>
        <!-- play icon for taskbar button -->
        <DrawingImage x:Key="PlayImage">
            <DrawingImage.Drawing>
                <DrawingGroup>
                    <DrawingGroup.Children>
                        <GeometryDrawing Brush="Black" Geometry="F1 M 50,25L 0,0L 0,50L 50,25 Z "/>
                    </DrawingGroup.Children>
                </DrawingGroup>
            </DrawingImage.Drawing>
        </DrawingImage>

        <!-- stop icon for taskbar button -->
        <DrawingImage x:Key="StopImage">
            <DrawingImage.Drawing>
                <DrawingGroup>
                    <DrawingGroup.Children>
                        <GeometryDrawing Brush="Black" Geometry="F1 M 0,0L 50,0L 50,50L 0,50L 0,0 Z "/>
                    </DrawingGroup.Children>
                </DrawingGroup>
            </DrawingImage.Drawing>
        </DrawingImage>

        // ... converters
        
    </Window.Resources>

    <Window.TaskbarItemInfo>
        <TaskbarItemInfo ... >
            
            <TaskbarItemInfo.ThumbButtonInfos>
                <ThumbButtonInfoCollection>

                    <!-- start button -->
                    <ThumbButtonInfo
                        ImageSource="{StaticResource ResourceKey=PlayImage}"
                        Command="{Binding StartCommand}"
                        CommandParameter="{Binding ActiveItem}"
                        Visibility="{Binding ActiveItem.IsActive, 
                                     Converter={StaticResource BoolToHiddenConverter}, 
                                     FallbackValue={x:Static Member=pc:Visibility.Visible}}"
                        />

                    <!-- stop button -->
                    <ThumbButtonInfo
                        ImageSource="{StaticResource ResourceKey=StopImage}"
                        Command="{Binding CancelCommand}"
                        CommandParameter="{Binding ActiveItem}"
                        Visibility="{Binding ActiveItem.IsActive, 
                                     Converter={StaticResource BoolToVisibleConverter}, 
                                     FallbackValue={x:Static Member=pc:Visibility.Collapsed}}"
                        />
                </ThumbButtonInfoCollection>
            </TaskbarItemInfo.ThumbButtonInfos>
        </TaskbarItemInfo>
    </Window.TaskbarItemInfo>

    // ....

</Window>

The applied XAML looks like this:

taskbar-buttons

Next Steps

The next post we’ll add some auditing capability to the pomodoro application using SQLite and the Entity Framework version in .NET 4.0.

Submit this story to DotNetKicks

Tuesday, December 29, 2009

Twelve Days of Code – Views

As part of the twelve days of code, I’m building a Pomodoro style task tracking application and blogging about it. This post is the fourth in this series -- we’ll look at some basic XAML for the View, data binding and some simple styling.

Some basic Layout

Our Pomodoro application doesn’t require a sophisticated layout with complex XAML.  All we really need is an area for our count down timer, and two buttons to start and cancel the Pomodoro.  That being said, we’ll drop a textbox and two buttons into a grid, like so:

<Window x:Class="Pomodoro.Shell.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Pomodoro" Width="250" Height="120">
    
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        
        <!-- active item -->
        <TextBlock Grid.Column="0"/>
        
        <!-- command buttons -->
        <StackPanel Orientation="Horizontal" Grid.Column="1">
            <Button Content="Start" />
            <Button Content="Stop" />
        </StackPanel>
        
    </Grid>
</Window>

Which looks something likes this:

Basic Pomodo - Yuck!

Binding to the ViewModel

The great thing behind the Model-View-ViewModel pattern is that we don’t need goofy “code-behind” logic to control the View.  Instead, we use WPF’s powerful data binding to graph the View to the ViewModel. 

There are many different ways to bind the ViewModel to the View, but here’s a quick and dirty mechanism until there’s a inversion of control container to resolve the ViewModel:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        var sessionController = new TaskSessionController();
        var alarmController = new TaskAlarmController();

        var ctx = new TaskApplicationViewModel(sessionController, alarmController);
        this.DataContext = ctx;
    }
}

The XAML binds to the TaskApplicationViewModel’s ActiveItem, StartCommand and CancelCommands:

<!-- active item -->
<TextBlock Text="{Binding ActiveItem.TimeRemaining}" />

<!-- command buttons -->
<StackPanel Orientation="Horizontal" Grid.Column="1">
    <Button Content="Start" 
            Command="{Binding StartCommand}" 
            CommandParameter="{Binding ActiveItem}"                 
            />
    <Button Content="Stop" 
            Command="{Binding CancelCommand}" 
            CommandParameter="{Binding ActiveItem}"
            />
</StackPanel>

The Count Down Timer

At this point, clicking on the Start button shows the pomodoro counting down in milliseconds.  I had considered breaking the count down timer into its own user control, but chose to be pragmatic and use a simple TextBlock.  The display can be dressed up using a simple converter:

namespace Pomodoro.Shell.Converters
{
    [ValueConversion(typeof(int), typeof(string))]
    public class TimeRemainingConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value is int)
            {
                int remaining = (int)value;

                TimeSpan span = TimeSpan.FromMilliseconds(remaining);

                return String.Format("{0:00}:{1:00}", span.Minutes, span.Seconds);
            }
            return String.Empty;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

Control Button Visibility

With the data binding so far, the Pomodoro application comes to life with a crude but functional user-interface.  To improve the experience, I’d like to make the buttons contextual so that only the appropriate button is shown based on the state of the session.  To achieve this effect, we bind to the IsActive property to control visibility state with mutually exclusive converters: BooleanToVisibleConverter and BooleanToCollapsedConverter.  I honestly don’t know why these converters aren’t part of the framework as I use this concept frequently. 

namespace Pomodoro.Shell.Converters
{
    [ValueConversion(typeof(bool), typeof(Visibility))]
    public class BooleanToHiddenConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value is bool)
            {
                bool hidden = (bool)value;
                if (hidden)
                {
                    return Visibility.Collapsed;
                }
            }
            return Visibility.Visible;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    [ValueConversion(typeof(bool),typeof(Visibility))]
    public class BooleanToVisibleConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value is bool)
            {
                bool active = (bool)value;

                if (active)
                {
                    return Visibility.Visible;
                }
            }
            return Visibility.Collapsed;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

However, there’s a Binding problem with all of these converters: by default, the ActiveItem of the TaskApplication is null and none of the bindings will take effect until after the object has been set.  This is easily fixed with a FallbackValue in the binding syntax:

<Window ...
        xmlns:local="clr-namespace:Pomodoro.Shell.Converters"
        xmlns:pc="clr-namespace:System.Windows;assembly=PresentationCore">

    <Window.Resources>
        <local:BooleanToVisibleConverter x:Key="BoolToVisibleConverter" />
        <local:BooleanToHiddenConverter x:Key="BoolToHiddenConverter" />
        <local:TimeRemainingConverter x:Key="TimeSpanConverter" />
    </Window.Resources>

    <Grid>

        <!-- active item -->
        <TextBlock Text="{Binding ActiveItem.TimeRemaining, Converter={StaticResource TimeSpanConverter}, 
                                  FallbackValue='00:00'}" />

        <!-- command buttons -->
        <StackPanel Orientation="Horizontal" Grid.Column="1">
            <Button Content="Start" 
                    Command="{Binding StartCommand}" 
                    CommandParameter="{Binding ActiveItem}"
                    Visibility="{Binding ActiveItem.IsActive, Converter={StaticResource BoolToHiddenConverter}, 
                    FallbackValue={x:Static Member=pc:Visibility.Visible}}"                   
                    />
            <Button Content="Stop" 
                    Command="{Binding CancelCommand}" 
                    CommandParameter="{Binding ActiveItem}"
                    Visibility="{Binding ActiveItem.IsActive, Converter={StaticResource BoolToVisibleConverter}, 
                    FallbackValue={x:Static Member=pc:Visibility.Collapsed}}"
                    />
        </StackPanel>

    </Grid>
</Window>

A few extra applied stylings, and the Pomodoro app is shaping up nicely:

Not so bad Pomodoro

Next Steps

The next post, I’ll look at some of the new Windows 7 integration features available in WPF 4.0.

Submit this story to DotNetKicks