You can do a lot of customizations on how the Windows Workflow Foundation designer will present your custom activities to the user with relatively minor work. For example, you can change the default text that gets shown on the activity (instead of the default which is the activity name), change the icon that is associated with the activity or change the size or internal alignment of text and icon.

You can do all of this without needing to step in and handle the painting of your activity in the designer yourself, which makes it quite a bit simpler. To do this, you'll want to create a custom ActivityDesigner-derived class and set or override its methods and properties as necessary. The most interesting properties here to manipulate are:

  1. Image: Contains the bitmap that is shown as part of your activity of your designer
  2. Text: contains the text that is displayed in the activity designer. By default, this will be the name given in the designer to the activity inside the workflow.
  3. Size: Defines the size that your activity will have in the designer.
  4. ImageRectangle, TextRectangle: These especify the rectangle where the image and text will be drawn at inside your activities. One thing to keep in mind when changing these is that they are specified in absolute coordinates inside the activity designer, not as relative to your activity's position in it. This means you'll want to calculate them based on the rectangle specified by the Bounds property of your activity designer.

You'll also probably want to implement your own ActivityDesignerThem-derived class and override there the colors and formats used by the workflow designer to paint your activity, such as what gradient colors or back color you want to use, what text color and so on.

Here's an example of a trivial activity whose designer draws it as a rounded square, with a larger icon on top and the text of the bottom:

//

// ConsoleActivity.cs

//

// Author:

//    Tomas Restrepo (tomasr@mvps.org)

//



using System;

using System.ComponentModel;

using System.ComponentModel.Design;

using System.Drawing;

using System.Drawing.Drawing2D;

using System.Workflow;

using System.Workflow.Activities;

using System.Workflow.ComponentModel;

using System.Workflow.ComponentModel.Design;





namespace CustomDesignerShapeDemo

{

   [Designer(typeof(ConsoleActivityDesigner), typeof(IDesigner))]

   public class ConsoleActivity : Activity

   {

      public static readonly DependencyProperty TextProperty =

         DependencyProperty.Register("Text", typeof(string), typeof(ConsoleActivity));



      /// <summary>

      /// Text to write to the console

      /// summary>

      public string Text

      {

         get { return (string)base.GetValue(TextProperty); }

         set { base.SetValue(TextProperty, value); }

      }



      protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)

      {

         Console.WriteLine(Text);

         return ActivityExecutionStatus.Closed;

      }

   } // class ConsoleActivity





   /// <summary>

   /// Customize the activity's appearance on the designer

   /// summary>

   [ActivityDesignerTheme(typeof(ConsoleActivityDesignerTheme))]

   public class ConsoleActivityDesigner : ActivityDesigner

   {

      readonly static Size BaseSize = new Size(96, 96);



      protected override Rectangle ImageRectangle

      {

         get { return CalcImageRectangle(); }

      }

      protected override Rectangle TextRectangle

      {

         get { return CalcTextRectangle(); }

      }



      protected override void Initialize(Activity activity)

      {

         base.Initialize(activity);

         Bitmap bmp = Properties.Resources.CommandLine1;

         bmp.MakeTransparent();

         Image = bmp;

      }



      protected override Size OnLayoutSize(ActivityDesignerLayoutEventArgs e)

      {

         base.OnLayoutSize(e);

         return BaseSize;

      }



      private Rectangle CalcImageRectangle()

      {

         Rectangle bounds = Bounds;

         Size sz = new Size(48, 48);



         Rectangle rcImg = new Rectangle();

         rcImg.X = bounds.Left + ((bounds.Width - sz.Width) / 2);

         rcImg.Y = bounds.Top + 4;

         rcImg.Size = sz;

         return rcImg;

      }



      private Rectangle CalcTextRectangle()

      {

         Rectangle bounds = Bounds;

         Rectangle imgRect = ImageRectangle;

         Size sz = Image.Size;



         return new Rectangle(bounds.Left + 2, imgRect.Bottom,

            bounds.Width-4, bounds.Height - imgRect.Height - 1);

      }



   } // class ConsoleActivityDesigner



   public class ConsoleActivityDesignerTheme : ActivityDesignerTheme

   {

      public ConsoleActivityDesignerTheme(WorkflowTheme theme)

         : base(theme)

      {

      }

      public override void Initialize()

      {

         base.Initialize();



         BorderColor = Color.FromArgb(251, 129, 6);

         BorderStyle = DashStyle.Solid;

         BackColorStart = Color.FromArgb(255, 128, 0);

         BackColorEnd = Color.FromArgb(255, 236, 217);

         BackgroundStyle = LinearGradientMode.ForwardDiagonal;

         ForeColor = Color.Black;

      }

   } // class ConsoleActivityDesignerTheme

} // namespace CustomDesignerShapeDemo

Unfortunately, one thing I think you cannot do here is specify the alignment for the text in the activity (it always gets drawn left-aligned), so if you need to change this you might to draw your activity yourself. You can do this by overriding the OnPaint() method in your activity Designer:

protected override void OnPaint(ActivityDesignerPaintEventArgs e)

{

   // ...

}

Have fun!


Tomas Restrepo

Software developer located in Colombia. Sr. PFE at Microsoft.