Assembly-level initialization at design time

April 7, 2010

One sorely missing feature from the Blend 4 Beta is the ability to have a method in which you can perform initialization work specific to design-time.  Such a method is useful for tasks like loading design-time data services into a container, configuring MEF with design-time specific dependencies, and basically anything else that you might otherwise do at startup when the application runs.  Since your App class won’t be started up when in design mode, it would be great if there was a way for Blend to call a method designated for that purpose at design-time.

I have been thinking about this a lot recently.  Initially I thought that Blend could provide an attribute that I could apply to a static method, and it would then invoke that decorated method before loading any Views.  That seemed like the best solution (and still does, in my opinion).  However, since Blend has no such attribute, I figured it was a moot point…until I realized that I could create my own attribute for the same purpose!

If you decorate an assembly with an attribute, that attribute must be instantiated when the assembly is inspected via reflection (which Blend most certainly does).  So, I simply created a custom attribute and applied it to my assembly.  In that attribute’s constructor, I check to see if it was loaded into design-time.  If it was, I then perform my initialization logic.  How simple!

Here’s the code I added to AssemblyInfo.cs in a project loaded by Blend 4 Beta:

I assume people might want to genericize this class a bit, but the basic idea is quite simple.  Perhaps adding a Type parameter for a class to instantiate would be better, so that the instantiated class could handle initialization.  That would leave the attribute very simple and reusable.  I’ll leave that up to you, if you care…

Here’s the code, for copy-and-paste purposes:

// In AssemblyInfo.cs
//
// Apply this attribute to the assembly so
// that it will be created when the assembly
// is loaded into memory.
[assembly: DesignTimeBootstrapper]

[AttributeUsage(AttributeTargets.Assembly)]
class DesignTimeBootstrapperAttribute
: Attribute
{
public DesignTimeBootstrapperAttribute()
{
var dep = new DependencyObject();
if (DesignerProperties.GetIsInDesignMode(dep))
{
// TODO: Design-time initialization…
}
}
}

Happy coding!


Design-time data is still data

April 4, 2010

It’s strange how common application architecture concerns are often ignored when it comes to supporting design-time data.  By “design-time data” I am referring to pre-canned/fake data that is shown in Views while they are being displayed and edited in Expression Blend, or the Visual Studio visual design surface (a.k.a. Cider).  There are two commonly seen approaches to supporting design-time data, each of which has severe drawbacks.

The most commonly seen approach is to use the d:DataContext and d:DesignInstance settings, which assign a designer-only data context for a View.  The d:DataContext setting is ignored at run-time.  This approach might seem great because it appears to keep design-time concerns consolidated in the View layer, which is the application layer in which “design-time” applies most directly.  Nothing could be further from the truth.  While having support for design-time data settings in the View layer might be great for early UI prototyping, it quickly becomes problematic as the rest of the application layers fall into place.  The main problem with d:DataContext is that you now have to maintain two separate data contexts: the real one and the design one.  Often people create entirely separate classes (or the designer tools generate dynamic classes) that mimic the real data objects and ViewModel objects that are used at run-time.  This introduces a grotesque amount of duplication in the code base, just for the sake of showing some fake data in Blend.  Having duplicated classes and extra settings in XAML just for the sake of design-time data strikes me as patently absurd.  Have fun maintaining that application over the years…

Another common approach to creating design-time data is to keep the Views unaware of being in design-time, and to have their ViewModel objects handle it for them.  This can easily lead to ViewModel classes that are littered with conditional logic that does one thing at design-time and something different at run-time.  For example, a ViewModel that exposes a collection of Foo objects might issue a network call to get Foos at runtime, but just new up a bunch of Foos at design-time.  Complicating ViewModels with repetitive conditional logic has a distinctly rotten code smell.  If a ViewModel is a Model of a View, and a View should not be smart enough to know about “design-time” then, by extension, neither should its Model (i.e. the ViewModel).  There has to be a better way!

Let’s take a step back and return to basics.  In a layered application architecture, you separate the responsibilities and concerns into various layers.  The View layer is responsible for showing things.  In MVVM, the ViewModel layer is responsible for maintaining the logical state of Views, and processing user interactions.  So far, we have not mentioned anything about data access.  That’s the job of a layer below the ViewModel, perhaps called the Model layer or the DataAccess layer.  If the application needs data, it goes to the DataAccess layer to get it.  Design-time data is still data.  It, too, should come from the DataAccess layer.  Everything above the DataAccess layer, such as ViewModels and Views, should not be responsible for making decisions about how data is accessed: including design-time data.

In an application that I’m working on these days, I created an interface that the ViewModel objects use to access data and save data.   It’s a modest sized application, so only one interface was needed so far.  In a larger system you could have as many interfaces as you need to meet your data access requirements.  The data access interface is implemented by three classes: one for run-time data access, one for design-time data access, and another for unit test-time data access.  I use dependency inversion (specifically, the Service Locator pattern) to supply an implementation of the data access interface to the ViewModels.  When the Views and ViewModels are created and start living their life, they are blissfully unaware of the run-time context in which they exist.  When running my unit tests, I provide the data access implementation with whatever data I want it to return to the ViewModel that invokes it.  The design-time implementation loads up some fake data from disk and passes it back into the ViewModels, which then bubbles it up to the Views on the design surface.   Of course, at run-time the “real” data access implementation is used to retrieve the actual data processed by the application.

To me, the primary benefit of this approach is that almost the entire system has no concept of “run-time” vs. “design-time” vs. “test-time.”  The only place in the code base that is aware of the run-time context is the tiny bit of code that determines which implementation of the data access interface to make available to the ViewModels.


Article about Service Locator, MVVM, and MessageBoxes

April 1, 2010

I just published an article titled ‘Using a Service Locator to Work with MessageBoxes in an MVVM Application‘ on CodeProject.  It’s one solution to the now canonical question of how to work with message boxes in an MVVM app, either WPF or Silverlight.  The article gives an introduction to the Service Locator pattern, in case you are not yet familiar with that concept, and then dives into an example of how to leverage it.  The end result is a simple, testable, extensible way to work with message boxes from ViewModel objects.

http://www.codeproject.com/KB/WPF/MessageBoxInMVVM.aspx

By the way, I found out today that I got the Microsoft MVP award again.  Four years in a row!  Woohoo!! :D


Follow

Get every new post delivered to your Inbox.

Join 287 other followers