Rehosting the Workflow Designer in WF4

Note: This blog post is written using the .NET framework 4.0 Beta 2

With Windows Workflow Foundation 3 it was possible to rehost the workflow designer in your own application. But possible is about all there was to say about it as it was pretty hard to do anything beyond the basics.


With Windows Workflow Foundation 4 live has become much better on the rehosting front [:)] In fact it is possible to create the fully functional and useful workflow editor below in about 200 lines of code. Now that is more like it!



The WorkflowDesigner

The WorkflowDesigner is the main class to work with. This exposes the actual design surface through the View property and the linked property sheet through the PropertyInspectorView property. Both these properties point to ready to use WPF UIElement’s so, as long as the host used WPF, adding them to a form is easy. And loading or saving a workflow is easy to, all it takes is a Load() and Save() function pointing to a XAML file. The code that does this part is below:

_workflowDesigner = new WorkflowDesigner();



var view = _workflowDesigner.View;

Grid.SetColumn(view, 1);

Grid.SetRow(view, 1);



var propInspector = _workflowDesigner.PropertyInspectorView;

Grid.SetColumn(propInspector, 2);

Grid.SetRow(propInspector, 1);




One thing that is needed is to register the workflow activity designer metadata. It is just a single call but leaving it out means all activities are just a small collapsed shape and won’t expand.

new DesignerMetadata().Register();


Displaying the toolbox with activities

The toolbox on the left if another standard WPF control called the ToolboxControl. Again easy to add to any WPF form. Add to it ToolboxItemWrapper with the activity type to add and you are good to go. Dragging controls onto the design surface just works, no extra work required. In the code below I just scan through all types in a few assemblies and if they are valid activities I add them to the toolbox. Again nice and easy.

var toolbox = new ToolboxControl();

var cat = new ToolboxCategory("Standard Activities");

var assemblies = new List<Assembly>();





var query = from asm in assemblies

            from type in asm.GetTypes()

            where type.IsPublic &&

            !type.IsNested &&

            !type.IsAbstract &&

            !type.ContainsGenericParameters &&

            (typeof(Activity).IsAssignableFrom(type) ||


            orderby type.Name

            select new ToolboxItemWrapper(type);


query.ToList().ForEach(ti => cat.Add(ti));


Grid.SetColumn(toolbox, 0);

Grid.SetRow(toolbox, 1);



The current selection

At the top of the form I display the currently selected activity and its parents. The WorkflowDesigner has an Items collection with a bunch of useful objects in there. One of these is a Selection object. We could periodically check this Selection but its even easier to subscribe to chances using the Subscribe() function and passing in a handler that is called whenever the selection changes. Setting up the subscription is another one-liner.


The handler itself isn’t very complex either.

private void SelectionChanged(Selection selection)


    var modelItem = selection.PrimarySelection;

    var sb = new StringBuilder();


    while (modelItem != null)


        var displayName = modelItem.Properties["DisplayName"];


        if (displayName != null)


            if (sb.Length > 0)

                sb.Insert(0, " - ");

            sb.Insert(0, displayName.ComputedValue);



        modelItem = modelItem.Parent;



    CurrentActivityName.Text = sb.ToString();



Validating the workflow

It would be nice to let the user know if the workflow is valid. Again quite easy to do by adding a IValidationErrorService to the WorkflowDesigner services collection. In this case I added a listbox to the form and let the IValidationErrorService add each error to the ListBox items. No need to call anything, the IValidationErrorService is automatically called as soon as anything in the workflow changes.

var validationErrorService = new ValidationErrorService(WorkflowErrors.Items);


The IValidationErrorService consists of a single function that gets the list of errors as a parameter.

public class ValidationErrorService : IValidationErrorService


    private IList _errorList;

    public ValidationErrorService(IList errorList)


        _errorList = errorList;



    public void ShowValidationErrors(IList<ValidationErrorInfo> errors)



        foreach (var error in errors)







Running the workflow

Just to be able to run the workflow I added a bit of code that uses a WorkflowApplication to run the workflow. Loading it is also easy, just call the ActivityXamlServices.Load() passing in the file and it will return a DynamicActivity ready to run.

var writer = new StringWriter();

var workflow = ActivityXamlServices.Load(_fileName);

var wa = new WorkflowApplication(workflow);


wa.Completed = WorkflowCompleted;

wa.OnUnhandledException = WorkflowUnhandledException;



So all together I have a working application that I can use to edit and run workflows. So who still needs Visual Studio 2010?

Sweet [:)]




10 thoughts on “Rehosting the Workflow Designer in WF4

  1. Rehosting the designer does appear to be much easier now, but without intellisense, is rehosting the designer and deploying it in a business scenario for the purpose of business users defining workflows realistic? Or is it simply up to the developer to provide activities that are so simplistic that a user only needs to type simple strings/ints etc.?

    Also, would the intention be that the business user is provided with a rehosted designer and a dll containing all necessary custom activities so that they can create/configure a workflow, and then the XAML is saved and either provided to a developer to validate and deploy, or the XAML is saved to a database so that the greater application infrastructure can then pull out the appropriate XAML and run the workflow when appropriate?

    I am looking at a scenario where workflow will be used to create a guided questionnaire to ultimately update a database (based on a decision at the end of the questionnaire), and want business users to be able to define the questionnaire – I guess at this stage I’m having trouble seeing how the rehosted designer, and the subsequent workflows that are created, would be used in the larger application (i.e. the questionnaire would be a single component in a much larger application)

  2. It is a nice post.
    One thing I noticed is that the ClearWorkFlowDesigner function may not be cleaning everything for the workflowDesigner instance.
    After open and close the demoworkflow.xaml several times. The memory consumption does go up. Any idea?

  3. Thank you for your article.
    I have another question, is it possible to rehosting workflow designer on web application ? I’m trying to figure out some link from msdn that discuss about the possibility or impossible to do so with standard WWF (or we must create the designer by some kind of HTML5)

  4. Thank you for this article.
    How could i comment an activity in this designer. Like we comment our codes.

    1. @Mohideen All my custom activities inherit from a BaseActivity class. This includes a property called IsEnabled which therefore becomes available to all my custom activities. Within each custom activities, I then check whether the IsEnabled in the Execute method and if it is not, I just skip all the code in there. The activity still gets called but it doesn’t do anything. I don’t know if this the right method, but it certainly works for me.

  5. Hi Maurice.
    I have a question, how to we add Flow Switch, Flow Desicion etc to the workflow designer toolbox. As on adding could not able to find it in Toolbox.

    Code Used:
    var cat = new ToolboxCategory(“Standard Activities”);

    var query = from asm in assemblies
    from type in asm.GetTypes()
    where type.IsPublic &&
    !type.IsNested &&
    !type.IsAbstract &&
    !type.ContainsGenericParameters &&
    (typeof(Activity).IsAssignableFrom(type) ||
    orderby type.Name
    select new ToolboxItemWrapper(type);

    query.ToList().ForEach(ti => cat.Add(ti));

Leave a Reply

Your email address will not be published. Required fields are marked *