Exercise 10: Hosted Designer

What if you wanted to create a custom activity like the PrePostSequence and have someone else who does not have Visual Studio use it? Many products allow end users to customize workflows. Windows Workflow Foundation 4 allows you to host the designer in an application quite easily. In this exercise, you will host the designer and use your custom activities.

Task 0 – Opening the Solution

To begin this exercise you can use the solution you finished from Exercise 9. Alternatively, you can follow the following steps to begin with Exercise 10.

  1. Start Microsoft Visual Studio 2010 from Start | All Programs | Microsoft Visual Studio 2010.
  2. Open the starting solution for Exercise 10 located under the Source\Ex10-HostedDesigner\Begin folder and use it as the starting point for this exercise.
  3. Press CTRL+SHIFT+B to build the solution.

Task 1 – Adding new WPF Application

  1. Right click on the HelloWorkflow solution and select Add / New Project…
  2. From the Windows templates Add new WPF Application named HelloDesigner
  3. Set the HelloDesigner project as the Startup project
  4. Add references to the following assemblies
    • System.Activities.Presentation
    • System.Activities.Core.Presentation
    • System.Activities
  5. From the Projects tab, add the following assemblies:
    • HelloWorkflow.Activities
    • HelloWorkflow.Activities.Designers
  6. Open MainWindow.xaml and modify it as shown

    (Code Snippet - Introduction to WF4LabMainWindow XAML CSharp)

    XAML (C#)

    <Window x:Class="HelloDesigner.MainWindow" xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="600" Width="1000"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="4*" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <Grid Name="grid1"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="4*" /> <ColumnDefinition Width="Auto" /> </Grid.ColumnDefinitions> </Grid> <TextBox Grid.Row="1" Name="textXAML" VerticalScrollBarVisibility="Visible" /> </Grid> </Window>

    (Code Snippet - Introduction to WF4LabMainWindow XAML VB)

    XAML (VB)

    <Window x:Class="MainWindow" xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="600" Width="1000"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="4*" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <Grid Name="grid1"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="4*" /> <ColumnDefinition Width="Auto" /> </Grid.ColumnDefinitions> </Grid> <TextBox Grid.Row="1" Name="textXAML" VerticalScrollBarVisibility="Visible" /> </Grid> </Window>

  7. Open MainWindow.xaml.cs (C#) or MainWindow.xaml.vb
  8. Add the following namespace directives

    (Code Snippet - Introduction to WF4LabMainWindow Namespaces CSharp)

    C#

    using System.Activities.Presentation; using System.Activities.Statements; using System.Activities.Presentation.Toolbox; using System.Activities.Core.Presentation; using System.Activities.Presentation.Metadata; using System.ComponentModel; using HelloWorkflow.Activities; using HelloWorkflow.Activities.Designers;

    (Code Snippet - Introduction to WF4LabMainWindow Namespaces VB)

    Visual Basic

    Imports System.Activities.Presentation Imports System.Activities.Statements Imports System.Activities.Presentation.Toolbox Imports System.Activities.Core.Presentation Imports System.Activities.Presentation.Metadata Imports System.ComponentModel Imports HelloWorkflow.Activities Imports HelloWorkflow.Activities.Designers

  9. Add a field of type WorkflowDesigner

    C#

    public partial class MainWindow : Window
    FakePre-20b48b0322f44a52872f6368bde08493-62950e5ef40548e3aceb10307f4c7747 WorkflowDesigner workflowDesigner = new WorkflowDesigner();

    Visual Basic

    Class MainWindow
    Private workflowDesigner As WorkflowDesigner = New WorkflowDesigner()

  10. Create a new function RegisterMetadata as shown. This function enables the designer metadata store.

    (Code Snippet - Introduction to WF4LabRegisterMetadata method CSharp)

    C#

    private void RegisterMetadata() { DesignerMetadata metaData = new DesignerMetadata(); metaData.Register(); AttributeTableBuilder builder = new AttributeTableBuilder(); MetadataStore.AddAttributeTable(builder.CreateTable()); }

    (Code Snippet - Introduction to WF4LabRegisterMetadata method VB)

    Visual Basic

    Public Sub RegisterMetadata() Dim metaData As DesignerMetadata = New DesignerMetadata() metaData.Register() Dim builder As AttributeTableBuilder = New AttributeTableBuilder() MetadataStore.AddAttributeTable(builder.CreateTable()) End Sub

    Note:
     When you host the designer you can control the toolbox. You choose what controls will appear, the categories they appear in and even the names of the controls. Add the CreateToolboxControl function as shown.

    (Code Snippet - Introduction to WF4LabCreateToolboxControl method CSharp)

    C#

    private ToolboxControl CreateToolboxControl() { return new ToolboxControl() { Categories = { new ToolboxCategory("Hello Workflow") { Tools = { new ToolboxItemWrapper( "System.Activities.Statements.Assign", "System.Activities, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", null, "Assign"), new ToolboxItemWrapper( "System.Activities.Statements.Sequence", "System.Activities, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", null, "Sequence"), new ToolboxItemWrapper( "System.Activities.Statements.TryCatch", "System.Activities, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", null, "Try It"), // Can use a different name new ToolboxItemWrapper( "HelloWorkflow.Activities.PrePostSequence", "HelloWorkflow.Activities", null, "PrePostSequence"), new ToolboxItemWrapper( "HelloWorkflow.Activities.DiagnosticTrace", "HelloWorkflow.Activities", null, "Diagnostic Trace") } } } }; }
    FakePre-fc66df980b574cec8d5a61575c3ab63d-7a61a16848764523bc20a7af0ccdc6b5FakePre-8e6fe75143004f1d91a70c8e68eaef94-1fc5dde45c94430db7b0f92b0d664064FakePre-871902ae8a3c49c09c6867ad2366f24a-c659cb6674194bd99fbc703fc6bf1d85
    

    (Code Snippet - Introduction to WF4LabCreateToolboxControl method VB)

    Visual Basic

    Private Function CreateToolboxControl() As ToolboxControl 'Create the ToolBoxControl Dim ctrl As ToolboxControl = New ToolboxControl() 'Create a collection of category items Dim category As ToolboxCategory = New ToolboxCategory("Hello Workflow") 'Creating toolboxItems category.Add(New ToolboxItemWrapper( "System.Activities.Statements.Assign", "System.Activities, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", Nothing, "Assign")) category.Add(New ToolboxItemWrapper( "System.Activities.Statements.Sequence", "System.Activities, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", Nothing, "Sequence")) category.Add(New ToolboxItemWrapper( "System.Activities.Statements.TryCatch", "System.Activities, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", Nothing, "Try It")) ' Can use a different name category.Add(New ToolboxItemWrapper( "HelloWorkflow.Activities.PrePostSequence", "HelloWorkflow.Activities", Nothing, "PrePostSequence")) category.Add(New ToolboxItemWrapper( "HelloWorkflow.Activities.DiagnosticTrace", "HelloWorkflow.Activities", Nothing, "Diagnostic Trace")) 'Adding the category to the ToolBox control. ctrl.Categories.Add(category) Return ctrl End Function
    FakePre-1b79afd4f7ed4aa0b81637666a2a8e32-cd7b64e26fab4745b156ae0f95cedceaFakePre-39d4b4c64a5a4ab5956c7464a3c64416-614fc920241547beb80e3c120c7b0ca8FakePre-f4259c74df03499dbc892a2dec179e73-df75dfbab3554adfa0c331dd15688f47FakePre-f622f59ef3cd47fa8d9a499966c2d2f1-73db9e063b7d4c079eeafeaceb1b724eFakePre-be3906f07193452aaddbcee6bee1c97c-e6aaa4cface34960a793abb96fc01c3bFakePre-a9b5558f7619458b8fe362d9d5ca0858-a7d2b044dae5414e804a5edf9b440270FakePre-3f3d8345f81d4904a30e6145fb08acb9-a8851e964e94442bba3218c1ce7cd90e
    

  11. Your Designer window will display the XAML of the workflow as it built. To do this you will need a function to handle the ModelChanged event. Add the ShowWorkflowXAML function as shown.

    (Code Snippet - Introduction to WF4LabShowWorkflowXAML method CSharp)

    C#

    private void ShowWorkflowXAML(object sender, EventArgs e) { workflowDesigner.Flush(); textXAML.Text = workflowDesigner.Text; }

    Visual Basic

    Private Sub ShowWorkflowXAML(ByVal sender As Object, ByVal e As EventArgs) workflowDesigner.Flush() textXAML.Text = workflowDesigner.Text End Sub

  12. Create the AddDesigner function as shown. This function will add the designer to your window

    (Code Snippet - Introduction to WF4LabAddDesigner method CSharp)

    C#

    private void AddDesigner() { //Create an instance of WorkflowDesigner class this.workflowDesigner = new WorkflowDesigner(); //Place the WorkflowDesigner in the middle column of the grid Grid.SetColumn(this.workflowDesigner.View, 1); // Show the XAML when the model changes workflowDesigner.ModelChanged += ShowWorkflowXAML; //Load a new Sequence as default. this.workflowDesigner.Load(new Sequence()); //Add the WorkflowDesigner to the grid grid1.Children.Add(this.workflowDesigner.View); // Add the Property Inspector Grid.SetColumn(workflowDesigner.PropertyInspectorView, 2); grid1.Children.Add(workflowDesigner.PropertyInspectorView); // Add the toolbox ToolboxControl tc = CreateToolboxControl(); Grid.SetColumn(tc, 0); grid1.Children.Add(tc); // Show the initial XAML ShowWorkflowXAML(null, null); }
    FakePre-aa21d7fce83d4266a4961ea957c5e507-adcecef290a64e30ad04c8380c8c7dc0FakePre-ebf68121c1b94560878e5ae09b1d70db-5b18e9d7ea034fea9ffb6f1c0a602772FakePre-0df9b6ef75264372aa6755ac9a9a487d-8e0f08d6d8384c9bb45dca749c24cab5FakePre-68889f5519ab4836aac8eb50bd31b401-00421dd6178741d584b2b684e6ef9756FakePre-b34100057a244f9fb86d7cff2fce36ee-94a12814edca45a1b461bab8183c2704FakePre-c5df3450d94841a4b883dbd06d04b8ff-0ac40647630546f6a36a665dbed6cb4eFakePre-062100da62834a338a6bfb1b4fd3bae6-f941e812da1a476f9275a671d716fa87
    

    (Code Snippet - Introduction to WF4LabAddDesignermethod VB)

    Visual Basic

    Private Sub AddDesigner() 'Create an instance of WorkflowDesigner class workflowDesigner = New WorkflowDesigner() 'Place the WorkflowDesigner in the middle column of the grid Grid.SetColumn(workflowDesigner.View, 1) ' Setup the Model Changed event handler AddHandler workflowDesigner.ModelChanged, AddressOf ShowWorkflowXAML 'Load a new Sequence as default. workflowDesigner.Load(New Sequence()) 'Add the WorkflowDesigner to the grid grid1.Children.Add(workflowDesigner.View) ' Add the Property Inspector Grid.SetColumn(workflowDesigner.PropertyInspectorView, 2) grid1.Children.Add(workflowDesigner.PropertyInspectorView) ' Add the toolbox Dim tc As ToolboxControl = CreateToolboxControl() Grid.SetColumn(tc, 0) grid1.Children.Add(tc) ' Show the initial XAML ShowWorkflowXAML(Nothing, Nothing) End Sub
    FakePre-42f9fde7b3d846e3a380355909a27e6a-ff0a6c73bd7f486cbc2c61a49b3d5b76FakePre-8a42ebd68a314180b709db5e18c996bd-0ca074e561254f8fa65135bf5c382adcFakePre-ed369bc323694ec48e1132b04e492927-fa3e1cdb363240e1bf3c750620c1f776FakePre-537e7e8c88d14732b09900e4818501b0-4d6f0b1c2772481d9ad35557e3bdc592FakePre-9f95760d8fca442e84efd1059efa0e3d-99847ed0bf24457fb8d16355057841d0FakePre-db64c313145c42d1954db76a5e6f5dee-586ae124ad9447f7aec9bfcf26d3e47cFakePre-5ac2337d97d1480d9da20b49d4c8bd99-dfa64196e9fc4118b682a64be2b88845FakePre-c841d2d48fb14e99b819c8793ab2164a-6508a722b36d42aa80ec48ff13dbd93d
    

  13. Modify the constructor to call the functions you added

    (Code Snippet - Introduction to WF4LabMainWindow method CSharp)

    C#

    public MainWindow() { InitializeComponent(); RegisterMetadata(); AddDesigner(); }

    (Code Snippet - Introduction to WF4LabMainWindow method VB)

    Visual Basic

    Public Sub New() InitializeComponent() RegisterMetadata() AddDesigner() End Sub

Next Step

Exercise 10: Verification