The Problem Solver

Tell me and I will forget
Show me and I will remember
Involve me and I will understand
- Confucius -

Google Ads

This Blog

Syndication

Search

Tags

News





  • View Maurice De Beijer's profile on LinkedIn

Community

Email Notifications

Explore

Archives

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 Smile 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!

image

 

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();
_workflowDesigner.Load(_fileName);
 
var view = _workflowDesigner.View;
Grid.SetColumn(view, 1);
Grid.SetRow(view, 1);
LayoutGrid.Children.Add(view);
 
var propInspector = _workflowDesigner.PropertyInspectorView;
Grid.SetColumn(propInspector, 2);
Grid.SetRow(propInspector, 1);
LayoutGrid.Children.Add(propInspector);

 

DesignerMetadata

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>();
assemblies.Add(typeof(Send).Assembly);
assemblies.Add(typeof(Delay).Assembly);
assemblies.Add(typeof(ReceiveAndSendReplyFactory).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) ||
            typeof(IActivityTemplateFactory).IsAssignableFrom(type))
            orderby type.Name
            select new ToolboxItemWrapper(type);
 
query.ToList().ForEach(ti => cat.Add(ti));
toolbox.Categories.Add(cat);
Grid.SetColumn(toolbox, 0);
Grid.SetRow(toolbox, 1);
LayoutGrid.Children.Add(toolbox);

 

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.

_workflowDesigner.Context.Items.Subscribe<Selection>(SelectionChanged);

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);
_workflowDesigner.Context.Services.Publish<IValidationErrorService>(validationErrorService);

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)
    {
        _errorList.Clear();
        foreach (var error in errors)
        {
            _errorList.Add(error.Message);
        }
    }
}

 

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.Extensions.Add(writer);
wa.Completed = WorkflowCompleted;
wa.OnUnhandledException = WorkflowUnhandledException;
wa.Run();

 

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 Smile

Enjoy!

www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu

Published Wed, Dec 23 2009 17:46 by Maurice
Filed under: , , , , ,

Comments

# Social comments and analytics for this post@ Saturday, December 26, 2009 8:30 PM

This post was mentioned on Twitter by mauricedb: Rehosting the Workflow Designer in WF4: Note: This blog post is written using the .NET framework 4.0 Beta ... http://bit.ly/5CFNn1 #MVPBuzz

# re: Rehosting the Workflow Designer in WF4@ Monday, December 28, 2009 5:46 PM

Argh...No intellisense in rehosted designer.  How would non-developers ever use it?

by James Holcomb

# re: Rehosting the Workflow Designer in WF4@ Tuesday, December 29, 2009 3:27 AM

@James,

IntelliSense is part of Visual Studio and as you mentioned doesn't work with the rehosted designer. However you can create and add a custom one using IExpressionEditorInstance and IExpressionEditorService and use that instead. See blogs.msdn.com/.../implementing-a-custom-expression-editor.aspx for an example.

by Maurice

# Cab + MEF@ Saturday, January 02, 2010 9:19 AM

Avec l’arrivée du Framework 4, une nouvelle brique fait son apparition : MEF ( Managed Extensibility

# re: Rehosting the Workflow Designer in WF4@ Thursday, January 14, 2010 11:48 PM

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)

by Johnson

# Memory does go up when open&close the demoworkflow.xaml@ Friday, March 12, 2010 1:46 PM

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?

Thanks.

Annie

by Annie

# Hosting the Workflow Designer is so much easier in .NET4 – a boon for the ISV community!@ Monday, June 21, 2010 1:44 PM

One of the most appreciated features of .NET Framework 4/Windows Workflow Foundation namespaces 

# Hosting the Workflow Designer is so much easier in .NET4 @ Saturday, July 31, 2010 6:07 AM

One of the most appreciated features of .NET Framework 4/Windows Workflow Foundation namespaces is the

# Rehosting Workflows@ Wednesday, February 06, 2013 9:49 PM

Rehosting Workflows