Creating Shapes with PathBuilder

In a previous post I showed a quick demo of a PathBuilder class I created to help draw dynamic shapes. I would like to include a simple example of how to create Shape controls using the same tool.

I have created a very simple Triangle control which you can download and see run.

Download Triangle Demo

Here is the actual Triangle class

class Triangle : Shape
{
    private Geometry geometry;

    public static readonly DependencyProperty P1Property = DependencyProperty.Register(
        "P1",
        typeof(Point),
        typeof(Triangle),
        new UIPropertyMetadata(OnPointChanged));

    public static readonly DependencyProperty P2Property = DependencyProperty.Register(
        "P2",
        typeof(Point),
        typeof(Triangle),
        new UIPropertyMetadata(OnPointChanged));

    public static readonly DependencyProperty P3Property = DependencyProperty.Register(
        "P3",
        typeof(Point),
        typeof(Triangle),
        new UIPropertyMetadata(OnPointChanged));

    public Point P1
    {
        get { return (Point)GetValue(P1Property); }
        set { SetValue(P1Property, value); }
    }

    public Point P2
    {
        get { return (Point)GetValue(P2Property); }
        set { SetValue(P2Property, value); }
    }

    public Point P3
    {
        get { return (Point)GetValue(P3Property); }
        set { SetValue(P3Property, value); }
    }

    private static void OnPointChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {
        ((Triangle)sender).UpdateGeometry();
    }

    private void UpdateGeometry()
    {
        this.geometry = PathBuilder.Start()
            .Move(P1)
            .DrawLine(P2)
            .DrawLine(P3)
            .DrawLine(P1)
            .Close()
            .ToGeometry();
    }

    public Triangle()
    {
        this.UpdateGeometry();
    }
        

    protected override Geometry DefiningGeometry
    {
        get 
        {
            return this.geometry;
        }
    }
}

Notice I inherited from Shape and use the PathBuilder to generate a Geometry object and return it in the protected DefiningGeometry property.

I had to add one method to my PathBuilder:

public static Geometry ToGeometry(this IPath path)
{
    var converter = new GeometryConverter();
    return (Geometry)converter.ConvertFromString(path.Data);
}

This method converts the path string into a Geometry object. Here is the xaml to display this control:

<c:Triangle P1="0,0" P2="0,100" P3="100,100" StrokeThickness="1" Stroke="Black" Fill="Blue" />

And finally the Triangle in action

image

WPF or Silverlight PathBuilder

Every once in a while you find yourself needing to draw some type of a shape dynamically. One easy example is arrows connecting visuals that are movable. In some cases you can simply place arrows where you expect the visuals to be but in others the visuals can move around in non-fixed ways. For those scenarios you need to create lines dynamically.

path_builder_example

In the composite screenshots above I am showing a scenario where I am able to drag the nodes around free form and I need the arrows to continuously update as the visual is moving to show relationships. You can imagine various other scenarios where you would need data driven shapes.

I have created a simple API for creating Path data in WPF or Silverlight. It is based on the idea that you can bind a string to the Data property of a Path object and all you need to do is to produce valid Path Data syntax in a string and you get a dynamic shape.

public enum SweepDirection
{
    Clockwise,
    CounterClockwise
}

public interface IPath
{
    string Data { get;}
}

public static class PathBuilder 
{
    private enum DrawCommand
    {
        Start,
        Move,
        Line,
        HorizontalLine,
        VerticalLine,
        CubicBezierCurve,
        QuadraticBezierCurve,
        SmoothCubicBezierCurve,
        SmoothQuadraticBezierCurve,
        EllipticalArc,
        Close
    }

    public static IPath Start()
    {
        return new Path(DrawCommand.Start, "");
    }

    private class Path : IPath
    {
        private DrawCommand lastCommand = DrawCommand.Start;
        private string data;
        public Path(DrawCommand command, string data)
        {
            this.lastCommand = command;
            this.data = data;
        }

        public string Data
        {
            get { return this.data; }
        }

        public DrawCommand Command
        {
            get { return this.lastCommand; }
        }
    }

    public static IPath Move(this IPath path, Point p)
    {
        var prefix = PathBuilder.AppendCommandPrefix(((Path)path).Command, DrawCommand.Move);
        return new Path(
            DrawCommand.Move, 
            path.Data + prefix + string.Format(" {0} {1}", p.X, p.Y));
    }

    public static IPath DrawLine(this IPath path, Point end)
    {
        var prefix = AppendCommandPrefix(((Path)path).Command, DrawCommand.Line);
        return new Path(
            DrawCommand.Line, 
            path.Data + prefix + string.Format(" {0} {1}", end.X, end.Y));
    }

    public static IPath DrawHorizontalLine(this IPath path, double x)
    {
        var prefix = AppendCommandPrefix(((Path)path).Command, DrawCommand.HorizontalLine);
        return new Path(
            DrawCommand.HorizontalLine,
            path.Data + prefix + string.Format(" {0}", x));
    }

    public static IPath DrawVerticalLine(this IPath path, double y)
    {
        var prefix = AppendCommandPrefix(((Path)path).Command, DrawCommand.VerticalLine);
        return new Path(
            DrawCommand.VerticalLine,
            path.Data + prefix + string.Format(" {0}", y));
    }

    public static IPath DrawCubicBezierCurve(this IPath path, Point controlPoint1, Point controlPoint2, Point end)
    {
        var prefix = AppendCommandPrefix(((Path)path).Command, DrawCommand.CubicBezierCurve);
        return new Path(
            DrawCommand.CubicBezierCurve,
            path.Data + prefix + string.Format(" {0} {1} {2} {3} {4} {5}",
                controlPoint1.X,
                controlPoint1.Y,
                controlPoint2.X,
                controlPoint2.Y,
                end.X,
                end.Y));
    }

    public static IPath DrawQuadraticBezierCurve(this IPath path, Point controlPoint, Point end)
    {
        var prefix = AppendCommandPrefix(((Path)path).Command, DrawCommand.QuadraticBezierCurve);
        return new Path(
            DrawCommand.QuadraticBezierCurve,
            path.Data + prefix + string.Format(" {0} {1} {2} {3}",
                controlPoint.X,
                controlPoint.Y,
                end.X,
                end.Y));
    }

    public static IPath DrawSmoothCubicBezierCurve(this IPath path, Point controlPoint, Point end)
    {
        var prefix = AppendCommandPrefix(((Path)path).Command, DrawCommand.SmoothCubicBezierCurve);
        return new Path(DrawCommand.SmoothCubicBezierCurve,
            path.Data + prefix + string.Format(" {0} {1} {2} {3}",
                controlPoint.X,
                controlPoint.Y,
                end.X,
                end.Y));
    }

    public static IPath DrawSmoothQuadraticBezierCurve(this IPath path, Point controlPoint, Point end)
    {
        var prefix = AppendCommandPrefix(((Path)path).Command, DrawCommand.SmoothQuadraticBezierCurve);
        return new Path(
            DrawCommand.SmoothQuadraticBezierCurve,
            path.Data + prefix + string.Format(" {0} {1} {2} {3}",
                controlPoint.X,
                controlPoint.Y,
                end.X,
                end.Y));
    }

    public static IPath DrawEllipticalArc(this IPath path, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection, Point end)
    {
        var prefix = AppendCommandPrefix(((Path)path).Command, DrawCommand.EllipticalArc);
        return new Path(
            DrawCommand.EllipticalArc,
            path.Data + prefix + string.Format(" {0} {1} {2} {3} {4} {5} {6}",
                size.Width,
                size.Height,
                rotationAngle,
                isLargeArc ? 1 : 0,
                sweepDirection == SweepDirection.Clockwise ? 0 : 1,
                end.X,
                end.Y));
    }

    public static IPath Close(this IPath path)
    {
        var prefix = AppendCommandPrefix(((Path)path).Command, DrawCommand.Close);
        return new Path(DrawCommand.Close, path.Data + prefix);
    }

    private static string AppendCommandPrefix(DrawCommand last, DrawCommand command)
    {
        if (last != command)
        {
            char c;
            switch (command)
            {
                case DrawCommand.Move:
                    if (last == DrawCommand.Move)
                        throw new InvalidOperationException("Cannot have two move commands in a row.");

                    c = 'M';
                    break;
                case DrawCommand.Line:
                    c = 'L';
                    break;
                case DrawCommand.HorizontalLine:
                    c = 'H';
                    break;
                case DrawCommand.VerticalLine:
                    c = 'V';
                    break;
                case DrawCommand.CubicBezierCurve:
                    c = 'C';
                    break;
                case DrawCommand.QuadraticBezierCurve:
                    c = 'Q';
                    break;
                case DrawCommand.SmoothCubicBezierCurve:
                    c = 'S';
                    break;
                case DrawCommand.SmoothQuadraticBezierCurve:
                    c = 'T';
                    break;
                case DrawCommand.EllipticalArc:
                    c = 'A';
                    break;
                case DrawCommand.Close:
                    if (last == DrawCommand.Close)
                        throw new InvalidOperationException("Cannot have two Close commands in a row.");

                    c = 'Z';
                    break;
                default:
                    throw new NotSupportedException();
            }

            return string.Format(CultureInfo.InvariantCulture, " {0}", c);
        }

        return string.Empty;
    }
}

 

Here is a snippet for drawing the arrows like I am doing above:

var pathData = PathBuilder.Start()
    .Move(start)
    .DrawCubicBezierCurve(cp1, cp2, end)
    .Move(end)
    .DrawLine(ap1)
    .Move(end)
    .DrawLine(ap2)
    .Data;

It’s a fluent interface that returns an immutable IPath for each draw call so you can reuse parts of paths and branch shapes without having to redraw the entire thing every time. I will leave it up to you to figure out where to put all of your points but the above snippet draws an arrow.

I am doing this code in my ViewModel in a string Property based on the state of my model and I am actually rendering it by Binding that to the Data property on a Path object. The related XAML snippet looks like this:

<Path 
    Data="{Binding PathData}" 
    Stroke="Black" 
    StrokeThickness="1" />

As strange as it seems the Data property can accept a string and when bound will redraw the path as the bound property changes.

ObservableObject for WPF MVVM

For those of you who know what INotifyPropertyChanged is and also know what kind of a maintenance burden the OnPropertyChanged(“Property”) calls are I would like to share my favorite implementation of the ObservableObject.

public class ObservableObject : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void SetAndNotify<T>(ref T field, T value, Expression<Func<T>> property)
    {
        if (!object.ReferenceEquals(field, value))
        {
            field = value;
            this.OnPropertyChanged(property);
        }
    }

    protected virtual void OnPropertyChanged<T>(Expression<Func<T>> changedProperty)
    {
        if (PropertyChanged != null)
        {
            string name = ((MemberExpression)changedProperty.Body).Member.Name;
            PropertyChanged(this, new PropertyChangedEventArgs(name));
        }
    }
}

Instead of using strings for property change notifications you use lambda expressions. This is beneficial because refactoring tools will pick this up instead of having to manually change the magic strings. It also will give you compile time errors if you have gotten something wrong. It also lets you maintain 1 statement setters in properties instead of multiple statements. Using the ObservableObject looks something like this:

public class Customer : ObservableObject
{
    private string name;

    public string Name
    {
        get { return this.name; }
        set { this.SetAndNotify(ref this.name, value, () => this.Name); }
    }
}

Simple and effective.

Silverlight 4 Runs Natively in .NET

This is a big deal.

I just learned this the other day and found surprisingly little information about it online. It was announced at PDC so it’s not a secret but it seems like a big deal to me. The feature is otherwise known as “assembly portability”.

When doing Silverlight one of the most frustrating things currently is the inability to run unit tests out of browser. This results in a break in continuous integration and a frustrating manual step in your testing process. Well no more!

This is only the beginning of the implications however. If you’re writing any application with a business logical layer, you should probably be writing it in Silverlight exclusively now. No more duplicating projects and creating linked file references. You can literally just create one project, compile it, and run it in both runtimes. Incredible.

Of course there are some limitations. But in this case I almost feel like the limitations are actually benefits. The thing is, you are likely to have features in one environment that are different or inaccessible in another. For example, file system access. In .net if you’re easily accessing the file system, but you might not be able to access it directly in Silverlight in the same way.

Enter System.ComponentModel.Composition. Otherwise known as MEF. By making your application logic composable you can solve all of the problems of framework differences and make your project imminently unit test friendly and better in general (if you buy into the principals of IoC at least).

For example, in Silverlight you cannot get a FileStream directly, you must make a call to OpenFileDialog which will give you the FileStream, if a user allows it. This is all well and good but when running in .net or unit tests you may want to allow it to access the file system directly or give it a mock stream instead. The solution is to make your calls to retrieve streams composable (otherwise known as dependency injection). Create a service interface, and create service instances for different environments.

For example, suppose you have the following (contrived) method in a Silverlight class:

public void DoWork()
{
    var dto = new SimpleDTO { Id = 100, Foo = "Hello World!" };

    Stream stream = Open();
    Save(stream, dto);

    stream = Open();
    dto = Load<SimpleDTO>(stream);

    Console.WriteLine("{0} : {1}", dto.Id, dto.Foo);
}

The process of opening a stream in Silverlight is different from the way it must be done when running in .net. So we make it composable.

public Stream Open()
{
    var stateService = container.GetExport<IStateService>().Value;
    stateService.State.Seek(0, SeekOrigin.Begin);
    return stateService.State;
}

Instead of opening the stream ourselves we import an exported service via MEF, that does know how to do it. To do this we simply need to have access to a container.

private CompositionContainer container;

public ComposableObject(CompositionContainer container)
{
    this.container = container;
}

Our constructor accepts a CompositionContainer as a parameter, which gives us access to all of the composable parts configured for our runtime. Keep in mind this is all Silverlight code at this point. And here is the IStateService.

public interface IStateService : IDisposable
{
    Stream State { get; }
}

The following code snippets are plain-old-dot-net-console-application snippets. First off, here is a snapshot of my solution explorer so you can see how things are structured.

image

You can see that I have created a reference from a Console Application project directly to a Silverlight 4 Class Library project. Visual Studio gives me a yellow banger, presumably because of the framework differences but it builds just fine. My program loads and calls my Silverlight library just this easily:

using SilverlightClassLibrary1;
class Program
{
    static void Main(string[] args)
    {
        var assembly = new AssemblyCatalog(typeof(Program).Assembly);
        using (var container = new CompositionContainer(assembly))
        {
            var co = new ComposableObject(container);
            co.DoWork();
        }

        Console.ReadKey(true);
    }
}

The bits at the beginning are creating a CompositionContainer using the current assembly. MEF allows you to load containers from all sorts of sources however, including entire directores full of Assemblies so you can have an easy add-in system. The ComposableObject is the one defined in my Silverlight Assembly! No interop nastiness, no AppDomain hassles, it just loads the dll as if it were true .NET code!

Next all I have to do is create an instance of the IStateService and export it.

[Export(typeof(IStateService))]
public class ParallelProcessingService : IStateService
{
    private Stream state;

    public Stream State
    {
        get
        {
            if (state == null)
                state = File.Create("state.dat");
            return state;
        }
    }

    public void Dispose()
    {
        if (state != null)
            state.Dispose();
    }
}

Now when I run this application, my Silverlight code will use MEF to load an Exported IStateService instance for me. Running this code will the access the FileSystem directly even though I’m running a Silverlight class library.

So what you should do is to create a Class Library with all of your logic, composed in a similar fashion as the above. Then in your Silverlight Application you simply implement and Export all of the Silverlight specific code as services. You do the same for your unit testing in .net projects and you’ll be able to run the exact same assembly in both locations.

The bonus to this, of course, is that you’ll also be able to swap out logic that you want to actually be different in different locations as well. For example, if you’re creating a business application you could put all of your business logic into a single assembly that could be run on both the client and the server. However, what that logic does and how it does it might be different in both locations. You may need to do a server call to a database to determine if a particular value of your business object is unique. On the client you want to make an asynchronous web request back to the server but on the server you want to make a call directly to the Database. It’s the same object and assembly in both locations so in order to achieve this you need to make the ValidateUnique rule itself composable, then this is possible even though the object is simply applying the rule in the same way.

In fact this technique can be very pervasive and powerful in general. Running on multiple frameworks requires you to be composable, which may also inadvertently force you into some good practices in general.

One other thing to note. I had to set CopyLocal=True for some of my references in the Silverlight Class Library to get it to run correctly in .NET. Since those assemblies aren’t in the GAC by default, it won’t load them unless they tag along with your assembly.

image

I didn’t test this out myself but you wouldn’t want those files appearing in your .xap file for your Silverlight application. I’m pretty sure that it would be smart enough to exclude them but double check.

Nullable TypeConverter for Silverlight

In Silverlight if you want a property of one of your Controls or Models to be Nullable<T> you will end up with a parser error without a little extra work. The reason for this is that there is no default TypeConverter for Nullable<T> so the parser doesn’t know how to convert the string in the Xaml to the appropriate type. To fix this you simply create your own TypeConverter and apply it to your property.

public class NullableTypeConverter<T> : TypeConverter
    where T : struct
{
    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        return sourceType == typeof(string);
    }

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
    {
        Nullable<T> nullableValue = null;
        string stringValue = value as string;
        if (!string.IsNullOrEmpty(stringValue))
        {
            T converted = (T)Convert.ChangeType(value, typeof(T), culture);
            nullableValue = new Nullable<T>(converted);
        }

        return nullableValue;
    }
}

Then to apply it you simply do the following:

[TypeConverter(typeof(NullableTypeConverter<int>))]
public int? Example { get; set; }

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.

Expression Photoshop Importer – By Soma

In his latest blog post Soma did a feature preview of the new version of Expression Web and the Photoshop importer gets an honorable mention.

http://blogs.msdn.com/somasegar/archive/2009/06/05/expression-web-3.aspx

With Expression Web 3, we have significantly improved capabilities and workflow when working with Photoshop files. When you import a PSD file, you can choose just the layers you want to import in to your website. You can save the layers as JPG, PNG, or GIF and scale the image* before saving the individual layers in Expression Web 3. If the source file has changed, Expression Web 3 prompts you to update it.

*Actually, you can’t scale the imported image in this window but you can zoom in or out of the preview to view it scaled and you can adjust the quality if you select jpeg. Once it is imported you can scale the dimensions of the image with your image editor of choice.

One interesting thing about the Photoshop Importer is that it is an expression wide feature rather than simply for Blend. Specifically it will be a feature available in Blend, Web and Design for this release. In each application the importer will have slightly different behavior. For example in the window shown here you can see there are options for Encoding and Quality as well as a field displaying the estimated size. When you import a Photoshop file in Web you will get a single flattened image rather than multiple resources like in Blend and Design.

Designing the importer so that it could be extended to support different feature sets for each application was one of my main roles so far. It was a lot of fun and I learned a lot!