Wednesday, July 23, 2008

Hacking Expression Blend

Adding Features and Plug-ins to Blend

To start with you will need to make sure Expression Blend is installed and we get a copy of the ‘Microsoft.Expression.Framework.dll’ which will be installed in the Microsoft Expression directory under program files or other location depending on how you installed. If you can’t find this directory you can do a global search on ‘Microsoft.Expression.Framework.dll’ and you will find it.

Now that you have the DLL we can now open Visual Studio and start a new project. For really hacking into Expression Blend so that our application or whatever it is you want to do in Blend we should use the WPF Custom Control Library project type found under the language of your choice (C# or VB.NET) and then under windows. Once the project is created drag a copy of the dll into the solution explorer and into the project. This DLL contains all the base class types used to wiring things into the Expression Blend infrastructure. Granted much of the stuff in Blend is sealed or closed there is enough available to us to be able to hack. You might ask since at the time of writing this the info was not publicly available or even privately available and since I’m not a Microsoftee how did I find this out…? Wel I want to thank a friend named Karim Hernandez with a little too much time on his hands and a nifty tool called ‘Reflector’ for finding this stuff out.

.NET Reflection and Probing the guts of .NET Binaries

A bit of topic but a critical skill to really pushing the limits to .NET programming in general is the albity to look into DLL’s and see what is there even if you are not provided documentation about what is in a binary. With .NET we have a built in technology for reading binary .NET content called reflection and through tools like ‘Reflector’ you can probe into the guts of things even if your not supposed to and using reflection or just referencing the DLL’s you can create instances of class’s you might not supposed to have. Case in point is sinsce Blend is a WPF application its DLL’s and binaries can be ‘probed’ and explored as it were and since this infrastructure is or will be probably available to control vendors at some point for extending blend we can go ahead and use it. However that being the case they could change and since we all know about .NET Reflection we can work it out.

Back to hacking Blend…

Now we need to create a reference to Blends Framework DLL so we can start implementing things we might want. Right click on our controls project and select ‘Add Reference’. You will need to select the Browse tab from the Reference dialog and then find the DLL we added to our project. Select it and click ‘OK’ which will not allow us to include references in the specific class’s. Start by renaming our ‘CustomControl1’ class to OurFirstBlendHack more for our own entertainment value. Visual Studio will ask about renaming all the references and you want to select yes so that the name change is clean and won’t break anything. Then at the top of the source fille add this line at the top:

using Microsoft.Expression.Framework.AddIn;
using Microsoft.Expression.Framework;

Now we have the ablity to start using the DLL content in our OWN classes how ever we want. We will start by making our Class a Blend Adding and in heriting from IaddIn which is the base class for Blends Framwork if you want to extend the functionality or add your own stuff into blend or whatever cool Silverlight tools you can think of. A real live use might be to integrate group Xaml/Silverlight editing tools like KaXaml or adding your own code formating or even a custom Silverlight control library. But first we need to make our first class definition look like this:

public class OurFirstBlendHack : IAddIn

And then add the detail meta data for Blend right before this first line like this:

[AddInDescription("OurFirstBlendHack", AddInCategory.Tool)]

With that we need to add a several methods to start mucking around with to deal with the StartUp event, Intialization, Dispose and the ShuttingDown event in Blend. The three events actually look like this:

public void Initialize(IApplicationService applicationService) { }

public void StartupComplete() { }

public void ShuttingDown() { }

public void Dispose() { }

Before we compile we also need also to remove the constructor or at least remove the line of code for setting the defaultKeySetter which will normally be added ‘for’ you as Visual Studio assumed this was inheriting from Control by default. Once the constructor is dealt with we then compile. Do this to make sure you have not made any errors but currently the class is valid but is not going todo anything. Our next step is to add some code and run it from Blend to see if we can make our ‘Addin’ work. Add the following line to our method StartupComplete.

MessageBox.Show("Blend is Hacked!");

Again this is not going todo anything until we run it from blend but if it is done then we should get a default windows dialog poping up with the label from our code. Todo this we need to make sure our code is compiled and then we need to open a command prompt test our code. Copy the DLL into the Blend directory and use the following at the command prompt:

Blend.exe /addin:HackingBlend.dll

This will start blend and blend will run the class we created and you will get the popup dialog ‘Blend is Hacked!’. If you really want to-do something as part of blend though, we might want to start with a menu. A custom menu in Blend is straight forward enough, but first let us build out what the menu will do. We can start this by making a command class. First create a new class in our project called HackCmd. Add the following includes at the top:

using Microsoft.Expression.Framework.AddIn;
using Microsoft.Expression.Framework;
using Microsoft.Expression.Framework.Commands;

Then we need to make the class inherit from the base command object like this:

internal class HackCmd : Command

To make the object actually do something we still need to add internal code to the class as well as the required API needs implemented to support usage. The main thing we want to implement then is the method Execute and our constructor. In this case this should look like the following Listing:

private IApplicationService _ApplicationService;

public HackCmd(IApplicationService ApplicationService)
_ ApplicationService = ApplicationService;

public override void Execute() { }

Now that we can Hack Blend lets close out the chapter summarizing what we learned. Next for testing lets add a line to Execute to actually do something like this:

MessageBox.Show("Blend is Hacked even more!");

This gives us something to call from our menu and from here we can open additional dialogs or WPF windows etc to perform whatever task we want to do. Remember then if you want a window for example to open you put it into the execute method of your command objects. To really make the menu work we still need one other class and that is a command target that receives menu events and routes them to the command class. Add a new class to your project called HackCmdTarget and add the additional using statements to top that you added to the HackCmd class. Then make sure we have our inheritance correct by making the class declaration look like:

internal class HackCmdTarget : CommandTarget

Now we need to fill out the guts of the class. In the case of the Target we are only adding a constructor and the references to the HackCmd class that we add to Blends command collection. The internal code then for our HackCmdTarget should be like the following listing:

internal static string HackCmdCommandName = "HackCmd_Command";

public HackCmdTarget(IApplicationService ApplicationService)
base.AddCommand(HackCmdTarget.HackCmdCommandName, new HackCmd(ApplicationService));

Now we can go back to the first class we created called OurFirstBlendHack and build out our Blend menu structure. Add the following line to add our command to blend when our class is loaded on Initialize to our class’s Initialize method:

ApplicationService.CommandService.AddTarget(new HackCmdTarget(ApplicationService));

Now Blend can see the target command and we can add a menu to call it. To create an instance of Blends menu we need to add a using statement to the top like this:

using Microsoft.Expression.Framework.UserInterface;

Then we can create an instance of the menu bar in blend and can add elements to the menu. Add the following line of code to the Initialization menu to create an instance of the menu like this:

ICommandBarMenu menu = ApplicationService.CommandBarService.CommandBars[0].Items.AddMenu("HackBlend", "HackBlend");

Now to add elements to our new menu we can call methods on our menu instance. In this case we can use ‘AddButton’ and ‘AddSeparator’ to build a little menu. Use these lines of code to add our elements and route our commands:

menu.Items.AddButton(HackCmdTarget.HackCmdCommandName, "alert us");
menu.Items.AddButton(HackCmdTarget.HackCmdCommandName, "another alert");

Now we can compile and then copy our DLL to the blend folder and run from the console the following line:

Blend.exe /addin:HackingBlend.dll

This will run Blend and run our little class in the context of Blend including our menu. If you try this you can see we have ‘hacked’ Blend or at least used its plug in framework to allow us to ‘extend’ Blend to do new and better stuff with our Silverlight Xaml. Now let us summarize what we have learned.

Also check out Karim's blog and post on topic at: