Click here to Skip to main content
15,885,141 members
Articles / Programming Languages / C#

Add Design Time Support to the WF Custom Activity Properties

Rate me:
Please Sign up or sign in to vote.
4.25/5 (4 votes)
11 Jun 2009CPOL5 min read 31.3K   218   12   2
This article shows how we can easily add the design time support to the WF custom activity properties

Introduction

Sometime when we develop our WF custom activity we'd like to have a "property design time" support to make the properties setting up process quicker. if you define a property on a custom activity, you can provide a custom user interface, or type editor, to edit the value of that property using a property browser. You can build a class called a designer that can manage a variety of aspects of a component or control's appearance and behavior at design time.

Using the Code

In this case, we are going to create a not very useful custom activity just to show how the property design time support works. To start, we are going to create a sequential workflow console application. We'll use this project to test our custom activity.Then we have to add a WorkFlow library project that contains our custom activity.

  1. Navigate to Start | All Programs | Microsoft Visual Studio 2005 | Microsoft Visual Studio 2005.
  2. Select the File | New | Project menu command.
  3. Visual Studio displays the New Project dialog box.
  4. Select the Visual C# | Workflow project type.
  5. Select Sequential workflow console application.
  6. Right click on the solution.
  7. Select add new Project.
  8. Click on WorkFlow | WorkFlow Library.

At this point, we should have something like that:

FirstStep.JPG - Click to enlarge image

The first step is to set up the base class of the custom activity. In this example, we create a simple custom activity so we have to set up System.Workflow.ComponentModel.Activity as the base class for the activity. To do that, just click on the activity property window then on base class property. A pop up will be shown, then select Activity as Type Name:

secondstep.JPG - Click to enlarge image

At this point, the aspect of the activity should look like the image below:

thirdStep.JPG

Now we are ready to start adding the code to the activity. In this example, we create an activity that prints the file path property on the screen. It's a completely useless activity but it's a good example to show how the design support for the property works. To start, we have to add the properties to our activity. In this case, we create just one property that contains the file path of the file. On the code view of the activity, add the code below:

C#
using System.ComponentModel;
using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Collections;
using System.Drawing;
using System.Linq;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel.Serialization;
using System.Workflow.Runtime;
using System.Workflow.Activities;
using System.Workflow.Activities.Rules;

namespace CustomActivityTester
{
    public partial class MyCustomActivity : System.Workflow.ComponentModel.Activity
    {
        public MyCustomActivity()
        {
            InitializeComponent();
        }
        public static DependencyProperty FilePathProperty =
		System.Workflow.ComponentModel.DependencyProperty.Register(
        "FilePath", typeof(string), typeof(MyCustomActivity));
        [Description("FilePath")]
        [Category("MyCustomActivity")]
        [Browsable(true)]

        [DefaultValueAttribute("False")]

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public string FilePath
        {
            get
            {
                return ((string)base.GetValue(MyCustomActivity.FilePathProperty));
            }
            set
            {

                    base.SetValue(MyCustomActivity.FilePathProperty, value);
              }
        }
    }
}

Now we could add our custom activity to the Visual Studio Tool Box. We have not finished developing it, but like that we can see how it works step by step.

  1. Right click on the toolbox.
  2. Select "Choose Item".
  3. Click on the browse tab.
  4. Select myCustomLibrary.dll from the custom activity project folder.

At this point, our activity should appear on the tool box:

fourthstep.JPG

Now drag and drop the activity on the workflow:

fifthstep.JPG

Select the activity and click on the property window. We can see the filePath property we have created. Visual Studio provides the standard way to set up the property. We can set it up by code or we can create either a property or a field to bind the property and then we can set it up through the code again:

C#
this.myCustomActivity1.FilePath = @"c:\MyFile.txt";

OR

sixthstep.JPG - Click to enlarge image

Now if we want make this task quicker we can add the design support for the FilePath property. Maybe in this case, it is not really necessary because we have to set up just a path of the file but this is just an example to show how this process works. The UI of the property setting is based on a simple Winform so as the first step we have to create a Winform where we design the interface and where we add the code to set up our property. To do it, right click on the MyCustomLibrary project and add a new window form to the project called "FilePathDesignSupport".

seventhstep.JPG

Now to avoid the user close the winform and resize, meantime setting up the FilePath property, we have to set up a couple of form's properties.

  1. Set up ControlBox=false.
  2. Set up FormBorderStyle="FixedSingle".

Now we can start designing the window form adding the controls we need to set up the property:

  1. Add a button called btnCancel
  2. Add a button called btnOk
  3. Add a button called btnBrowse
  4. Add a label called lblFileName
  5. Add a label called lblFileSelected

eightstep.JPG

Add this code to the form's code:

C#
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace MyCustomLibrary
{
    public partial class FilePathDesignSupport: Form
    {
        public FilePathDesignSupport()
        {
            InitializeComponent();
        }
        private string _fileName = string.Empty;
        public string FileName
        {
            get
            {
                return _fileName;

            }
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            this.lblFileSelected.Text = string.Empty;
            this._fileName = string.Empty;
            this.Close();
        }

        private void btnOk_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void btnBrowse_Click(object sender, EventArgs e)
        {
            this.openFileDialog1.ShowDialog();
        }

        private void openFileDialog1_FileOk(object sender, CancelEventArgs e)
        {
            if (string.IsNullOrEmpty(this.openFileDialog1.FileName) == false)
            {
                this.lblFileSelected.Text = this.openFileDialog1.FileName;
                this._fileName = this.lblFileSelected.Text;

            }
            else
            {
                this.lblFileSelected.Text = string.Empty;
                this._fileName = string.Empty;
            }
        }
    }
}

Now the UI to set up the FilePath property is ready. The next step is to create a class that "manages" the visualization of the UI we created before then we have to add an attribute to tell the Visual Studio designer which is the control to show when the user wants to set up the property. The "UI Manager" is represented by a class that inherits from "UITypeEditor".

Shown below is how to implement that class:

C#
using System.ComponentModel;
using System;
using System.ComponentModel.Design;
using System.Collections;
using System.Drawing;
using System.Linq;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel.Serialization;
using System.Workflow.Runtime;
using System.Workflow.Activities;
using System.Workflow.Activities.Rules;
using System.Drawing.Design;
using MyCustomLibrary;

namespace CustomActivityTester
{
    public partial class MyCustomActivity : System.Workflow.ComponentModel.Activity
    {
        public MyCustomActivity()
        {
            InitializeComponent();
        }
        public static DependencyProperty FilePathProperty =
		System.Workflow.ComponentModel.DependencyProperty.Register(
        "FilePath", typeof(string), typeof(MyCustomActivity));
        [Description("FilePath")]
        [Category("MyCustomActivity")]
        [Browsable(true)]
        [DefaultValueAttribute("False")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [Editor(typeof(DriveEditor), typeof(UITypeEditor))]
        public string FilePath
        {
            get
            {
                return ((string)base.GetValue(MyCustomActivity.FilePathProperty));
            }
            set
            {
                    base.SetValue(MyCustomActivity.FilePathProperty, value);
            }
        }
        protected override ActivityExecutionStatus Execute
			(ActivityExecutionContext executionContext)
        {
        Console.WriteLine(string.Concat("The File path is: ",this.FilePath));
        return ActivityExecutionStatus.Closed;
        }
    }

    public class DriveEditor : UITypeEditor
    {
        public override System.Drawing.Design.UITypeEditorEditStyle
        GetEditStyle(System.ComponentModel.ITypeDescriptorContext context)
        {
            // We will use a window for property editing.
            return UITypeEditorEditStyle.Modal;
        }

        public override object EditValue(
        System.ComponentModel.ITypeDescriptorContext context,
        System.IServiceProvider provider, object value)
        {
            FilePathDesignSupport frm = new FilePathDesignSupport();

            //Show the UI to set up the property
            frm.ShowDialog();

            // Return the file name of the file selected.
            return frm.FileName;
        }

        public override bool GetPaintValueSupported(
        System.ComponentModel.ITypeDescriptorContext context)
        {
            // No special thumbnail will be shown for the grid.
            return false;
        }
    }
}

The most important method of the UITypeEditor class is the EditValue method. It tells Visual Studio what to do when the user clicks on the property window to set up the property. In this case, we create an instance of the FilePathDesignSupport form then we just show it. This method has to return an object that represents the value of the property we were setting up. In this case, we return the file path of the file selected. After that, we have to "Bind" the property "FilePath" with the class that represents the UI to show. To do it, we have to just add this attribute in the FilePath property [Editor(typeof(DriveEditor), typeof(UITypeEditor))]. At this point, everything is done. If we click on the custom activity on the workflow, then on the FilePath property the FilePath form will be shown to set up the property. At the end, we can override the Execute method of the Activity class. This is the method that contains the code to implement the behavior of the activity.The runtime will call this method meantime the activity is executed on the workflow. In this case, we just print on  the screen the value of the FilePath property.

thelast.JPG - Click to enlarge image

As we see in this article, it's quite easy to add design support for the custom activity properties. We can use this way every time we want to make the property setting up process quicker or maybe we want to help the user to set up the properties.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect PeluSoft Limited
United Kingdom United Kingdom
I have been fascinated by software development since I was 10 years old. I'm proud of learned the first programming language with an Olivetti PC 128S based on Microsoft BASIC. I'm a Software Architect/Senior Developer with a strong background of all the developing Microsoft's technologies.

Comments and Discussions

 
QuestionDependencyProperty and not an InArgument<string> ? Pin
Stephen Brannan21-Jun-12 11:19
Stephen Brannan21-Jun-12 11:19 
GeneralMy vote of 5 Pin
steliodibello8-Dec-10 11:40
steliodibello8-Dec-10 11:40 
nice one!

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.