« Africa Flight Adventure | Main | How To Use MarkupExtension For A String Resource That Defines A Gesture »
Tuesday
Jun082010

How To Create An External MarkupExtension Assembly

In a previous article I noted that the Visual Studio's development team expects Markup Extensions to be imported from an external assembly, rather than defined local within the project.

"... package your custom markup extension into a separate assembly ... this is the recommended way to create and consume such custom markup extensions."

Obviously our next task, then, is to explore how one goes about packaging a markup extension in a separate assembly. For this example we'll use the GestureExtension from the aforementioned article.

Only Visual Studio 2010 Need Apply

Note that this tutorial provides the most value if you're using Visual Studio 2010. Users of Visual Studio 2008 may not be motivated to bother, as per the subsequent comments from the Visual Studio development team:

"We do not plan to release a fix for this issue in Visual Studio 2008. It will remain a limitation of the WPF designer in Visual Studio 2008 that it cannot load designs with references to custom markup extensions."

Names & Namespaces

Before we begin, I wish to clarify the names used for the various stages in this project.

Library Name: GestureMarkupExtensionLibrary
Primary Namespace: GestureMarkupExtension
Class Name: GestureExtension

Don't get these mixed up, or the library assembly won't work.

Step-By-Step

Creating The Library Project

  1. From the File menu, choose New Project...

  2. In the New Project dialog, choose Class Library and enter the name "GestureMarkupExtensionLibrary". Click OK.

  3. The starting library project will not include some of the assembly references we will require, so we'll need to add them. From the Solution Explorer, right-click on the References folder and choose Add Reference...

  4. In the Add Reference dialog, switch to the .NET tab.

  5. In the Component Name column, find PresentationCore. Select it, and click OK. This assembly will appear among the items in the References folder.

  6. Repeat to add a reference for the PresentionFramework and WindowsBase assemblies.

  7. If you're running Visual Studio 2010 you'll also need to add a reference for the System.Xaml assembly.

Creating The GestureExtension Class

  1. From the Solution Explorer, right-click the "Class1.cs" source file. From the pop-up menu click Delete. Yes, we wish to delete this permanently.

  2. Still in the Solution Explorer, right-click the GestureMarkupExtensionLibrary project label (in bold). From the pop-up menu expand the Add menu and choose Class...

  3. In the Add New Item dialog, enter the name "GestureExtension" and click Add. The source file "GestureExtension.cs" will be added to the project and loaded into the editor.

  4. To make this simple, clear the boilerplate code from the source file and replace it with the following:

    using System;                   // IServiceProvider
    using System.Windows; // DependencyObject
    using System.Windows.Input; // KeyBinding, KeyGesture, KeyGestureConverter
    using System.Windows.Markup; // MarkupExtension, IProvideValueTarget

    namespace GestureMarkupExtension
    {
    public class GestureExtension : MarkupExtension
    {
    public GestureExtension(object gesture)
    {
    _gesture = gesture as string;
    if (String.IsNullOrEmpty(_gesture))
    {
    _gesture = String.Empty;
    }
    }

    private string _gesture;

    public override object ProvideValue(IServiceProvider service)
    {
    var target = (IProvideValueTarget)service.GetService(typeof(IProvideValueTarget));
    DependencyObject targetObject = target.TargetObject as DependencyObject;

    // If the current XAML object is a KeyBinding, construct a KeyGesture.
    if (targetObject is KeyBinding)
    {
    // The KeyGestureConverter conveniently does the work for us.
    KeyGestureConverter kgc = new KeyGestureConverter();

    // Unfortunately, there doesn't seem to be any way to specify the
    // KeyGesture.DisplayString property, as this is assignable only
    // from the KeyGesture constructor. Still, I found no evidence that
    // this would actually provide any benefit with respect to the UI behavior.
    KeyGesture g = kgc.ConvertFromString(_gesture) as KeyGesture;
    return g;
    }

    // Else, simply return the string specified in the XAML.
    return _gesture;
    }
    }
    }

    The logistics of this code are described in this previous article.

Creating The Library DLL

  1. From the Solution Explorer highlight the Solution 'GestureMarkupExtensionLibrary'.

  2. From the File menu, choose Save GestureMarkupExtensionLibrary.sln.

  3. In the Save Project dialog, Browse to the desired folder, if necessary. The Name should already be set as "GestureMarkupExtensionLibrary". Click Save. Remember where you saved this.

  4. If the you're able to, choose the Release build configuration for the project. If you don't see a means to select a build configuration (this is an "advanced" feature which is initially hidden by Visual Studio) then you can safely skip this step.

  5. From the Build menu, choose Build Solution.

We're done with the library. From the File menu, choose Close Solution.

Configuring The 'Other' Project To Use The Separate Assembly

  1. From the File menu, choose Open Project... Load the solution containing the project in which you want to utilize the markup extension.

  2. If you've already got a local copy of the markup extension class in the project, right-click on its class file in the Solution Explorer and choose Exclude From Project.

  3. From the Solution Explorer, right-click on the References folder label and choose Add Reference...

  4. In the Add Reference dialog, switch to the Browse tab.

  5. Browse to the GestureMarkupExtensionLibrary project folder you saved earlier.

  6. Click through to the "bin" folder, and then through to the "Release" folder. Select the "GestureMarkupExtensionLibrary.dll" and click OK.

    (If you don't find the DLL in the Release folder, try the Debug folder.)

  7. In the XAML for your UI's Window, add an entry to the Window tag to register the GestureMarkupExtension namespace.

    <Window ...
    xmlns:gesture="clr-namespace:GestureMarkupExtension;assembly=GestureMarkupExtensionLibrary"
    ... >

The Gesture extension is now available to your XAML. The syntax is exactly the same as if the markup extension was defined locally, but for the advantage that the Visual Studio Designer will not generate spurious errors.

PrintView Printer Friendly Version

EmailEmail Article to Friend