Ship It!

phone 033

 

Because my phone sucks so bad it’s a tiny picture but this is my first Ship It award from Microsoft for being apart of the team that shipped Expression Studio 3. Also, even though it looks like copper its actually a metallic silver. The inscriptions says:

Ship It

Every time a product ships, it takes us one step closer to the vision: empower people through great software-any time, any place and on any device. Thanks for the lasting contribution you have made to Microsoft History.

Steve Ballmer    Bill Gates

Justin Chase

 

Thanks Steve and Bill!

OMeta

If you haven’t heard of it check this out:

http://www.tinlizzie.org/ometa/

I was just reading his Ph.D. dissertation linked on that page and this quote is really jumping out at me:

OMeta’s key insight is the realization that all of the passes in a traditional compiler are essentially pattern matching operations:
• a lexical analyzer finds patterns in a stream of characters to produce a stream of tokens;
• a parser matches a stream of tokens against a grammar (which itself is a collection of productions, or patterns) to produce abstract syntax trees (ASTs);
• a typechecker pattern-matches on ASTs to produce ASTs annotated with types;
• more generally, visitors pattern-match on ASTs to produce other ASTs;
• finally, a (naive) code generator pattern-matches on ASTs to produce code.

He is so right. It seems that pattern matching might be the other side of the coin of Transformation. Great stuff.

Easy Composable Theming in WPF (.NET 4)

In .NET 4 there is a new namespace to be aware of and that is System.ComponentModel.Composition. Also known as MEF (Managed Extensibility Framework). This post outlines a very simple way to take advantage of the new Composition tools to add simple themeing to your WPF applications.

http://cid-dfcd2d88d3fe101c.skydrive.live.com/embedrowdetail.aspx/blog/justnbusiness/ComposableThemes.zip

 

 image image

 

Step 1: Create a shared project

The shared project should define interfaces and classes that are needed by both the application and each of the composable parts. In this sample application I have a project called Core which defines a single interface. All other projects reference this core project.

IThemeService.cs

namespace Core
{
    public interface IThemeService
    {
        ResourceDictionary Theme { get; }
    }
}

 

Step 2: Create Theme Projects

A theme project will reference the core project and implement the IThemeService interface.

ThemeXService.cs

using System.ComponentModel.Composition;
using Core;

namespace ThemeX
{
    [Export("ThemeX", typeof(IThemeService))]
    internal class ThemeXService : IThemeService
    {
        public System.Windows.ResourceDictionary Theme
        {
            get { return new Themes.Generic(); }
        }
    }
}

Additionally this project will contain a single resource dictionary class with all of our named resources defined.

Themes\Generic.xaml

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:system="clr-namespace:System;assembly=mscorlib"
    xmlns:local="clr-namespace:ThemeX"
    x:Class="ThemeX.Themes.Generic">

    <system:String x:Key="ThemeTitle">Theme X!</system:String>
    <SolidColorBrush x:Key="ThemeBrush" Color="PowderBlue" />
</ResourceDictionary>

Themes\Generic.cs

using System.Windows;

namespace ThemeX.Themes
{
    public partial class Generic : ResourceDictionary
    {
        public Generic()
        {
            this.InitializeComponent();
        }
    }
}

 

Step 3: Create Your Application and Load a Theme

In this application I am loading the first theme at startup then changing the theme based on a selection of a ComboBox. In a real application it might make more sense to store the name of the theme in user settings somehow and load the theme using that value.

Here is the very simple window that is to be themed.

MainWindow.cs

<Window 
    x:Class="ComposableThemes.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:app="clr-namespace:ComposableThemes"
    Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="auto" />
            <RowDefinition />
        </Grid.RowDefinitions>
        <ComboBox ItemsSource="{Binding ThemeNames, Source={x:Static app:App.Current}}"
                SelectionChanged="ComboBox_SelectionChanged" />
        <Border 
            Grid.Row="1"
            Margin="25"
            BorderThickness="2"
            CornerRadius="5"
            Background="{DynamicResource ThemeBrush}">
            <TextBlock 
                HorizontalAlignment="Center"
                VerticalAlignment="Center"
                Text="{DynamicResource ThemeTitle}" />
        </Border>
    </Grid>
</Window>

Notice the {DynamicResource …} references. These will give warnings in your design view because they cannot be resolved. They will be resolved at runtime because we will be loading the resource dictionary object created in step 2 at startup.

Here is how you can load an exported object and load a resource dictionary at runtime.

App.xaml.cs

public void SetTheme(string themeName)
{
    string location = Path.GetDirectoryName(typeof(App).Assembly.Location);
    using (var addinCatalog = new DirectoryCatalog(location))
    {
        using (CompositionContainer container = new CompositionContainer(addinCatalog))
        {
            if (!string.IsNullOrEmpty(themeName))
            {
                IThemeService theme = container.GetExport<IThemeService>(themeName).Value;
                if (theme != null)
                {
                    var themeDictionary = theme.Theme;
                    if (themeDictionary != null)
                    {
                        this.Resources.MergedDictionaries.Add(themeDictionary);
                    }
                }
            }
        }
    }
}

In this method we are using the applications directory to look for composable parts (plug-ins). A catalog is basically a container that loads assemblies and finds Exports / Imports for you. There is a very handy AggregateCatalog class that will allow you to have multiple directories or multiple assemblies or whatever type of catalog you want.

It’s useful to know that you can also use an Import attribute on a class to have the container automatically bind together the imported and exported parts. I find that to be a little more magical than I prefer so I did it this way instead.

Also, you can get a list of all theme names by inspecting the metadata of exported parts. Here is a snippet I used to populate my ComboBox with theme names:

App.xaml.cs

public IEnumerable<string> ThemeNames
{
    get
    {
        string location = Path.GetDirectoryName(typeof(App).Assembly.Location);
        using (var addinCatalog = new DirectoryCatalog(location))
        {
            foreach (var part in addinCatalog.Parts)
            {
                foreach (var definition in part.ExportDefinitions)
                {
                    var value = (string)definition.Metadata["ExportTypeIdentity"];
                    if (value == typeof(IThemeService).FullName)
                    {
                        yield return definition.ContractName;
                    }
                }
            }
        }
    }
}

 

Conclusion

All in all, I am very happy with the new Composition framework. It’s very easy to use and because of that, very powerful. One thing you should keep in mind however is that there is no magic here when it comes to loading and unloading assemblies, if you use a directory catalog it will load all assemblies in that directory into your current AppDomain and you cannot unload them (as is normal).

For another example of MEF in action check out my MetaTask in the MetaSharp source code. This is how all pipelines are loaded in MetaSharp.