Oct 7 2010

Icon support for custom Windows Workflow activities

Category: .NetRory Primrose @ 06:25

Creating a custom dependency resolution activity for WF gave me the opportunity to learn a lot about the latest version of Workflow Foundation. Adding support for custom icons is a simple requirement that often came up when creating new activities.

There are two places that provide this icon support. The first is in the Visual Studio toolbox and the second is on the activity design surface. I have been using images from the awesome famfamfam Silk collection for these activities.

Visual Studio toolbox

Adding an icon to the toolbox is done using the ToolboxBitmapAttribute on the activity class.

[ToolboxBitmap(typeof(ExecuteBookmark), "book_open.png")]
public sealed class ExecuteBookmark : NativeActivity

This attribute needs to identify the image file and a type reference that the IDE uses to locate the image. In the above scenario, the book_open.png file is the image to use for the toolbox. The image file in the project needs to have its Build Action property set to Embedded Resource.

image

The IDE uses the type reference to determine the namespace used as the prefix of the image name in the assembly resources list.

image

The IDE can then extract this image and use it in the toolbox.

image

Workflow designer

The workflow designer support for custom icons has a similar layout as the toolbox icon. The image file for the designer should be co-located with the designer xaml file. While this file should be the same image as the toolbox image, the file must be a different file reference in the Visual Studio solution/project. Adding the image file as a link to the other file should work if you want to have only one physical file for the image.

The reason for the separate file is that the Build Action for the designer image must be set to Resource instead of Embedded Resource that the ToolboxBitmapAttribute requires. Using two files for this purpose should not be a big issue as the designers are typically located in a separate *.Design.dll assembly (see here for the details).

image

The XAML in the designer for the activity then references this image file.

<sap:ActivityDesigner x:Class="Neovolve.Toolkit.Workflow.Design.Presentation.ExecuteBookmarkDesigner"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:sap="clr-namespace:System.Activities.Presentation;assembly=System.Activities.Presentation"
    xmlns:sapv="clr-namespace:System.Activities.Presentation.View;assembly=System.Activities.Presentation">
  <sap:ActivityDesigner.Icon>
    <DrawingBrush>
      <DrawingBrush.Drawing>
        <ImageDrawing>
          <ImageDrawing.Rect>
            <Rect Location="0,0" Size="16,16" ></Rect>
          </ImageDrawing.Rect>
          <ImageDrawing.ImageSource>
            <BitmapImage UriSource="book_open.png" ></BitmapImage>
          </ImageDrawing.ImageSource>
        </ImageDrawing>
      </DrawingBrush.Drawing>
    </DrawingBrush>
  </sap:ActivityDesigner.Icon>
</sap:ActivityDesigner>

The designer should then be associated with the activity. This is done using a class that implements IRegisterMetadata so that there can be a separation of the activity assembly and the design assembly. Again, see this post for the details.

image

The designer will look at the design assembly and extract the image from the resource list. This image will then be used on the design surface.

image

The only other thing to keep in mind is that the design assembly must be co-located with the activity assembly in order to leverage the design-time experience provided by the custom activity designers.

Tags:

Comments (2) -

1.
Rory Primrose Rory Primrose Australia says:

I have done some initial testing with the linked images suggestion and it does not seem to work. I linked the activity assembly images into the design assembly and they did not get loaded by the designer. The images failed to get loaded by the designer in the following scenarios:

- Design surface of the activity designer itself
- Design surface that holds an activity using the designer where the designer is in another project of the same solution
- Design surface that holds an activity using the designer where the designer and activity are binary references

The last point is a deal-breaker. I also don't understand why it doesn't work because the XAML of the designer hasn't changed and the assembly has been correctly compiled with the linked images in the resource.

2.
Rory Primrose Rory Primrose Australia says:

Another update - I was a little wrong on the last comment. The fact that point #3 above didn't work bugged me as there should be no difference at the binary level. I put in another attempt and found that I didn't hook up my activity under development using IRegisterMetadata.

The image now seems to get loaded and displayed in the designer once I fixed this. The image is not displayed for an activity in another project in the solution (#2 above) and for a binary reference (3# above). The image still does not get displayed in the activity designer itself (#1 above) but this is not really a problem. I can understand that this was a feature overlooked by the product team and really isn't that important.

So overall, I would say that linked image files are worthwhile because there will only be one copy of the image used for the toolbox and the designer. This will make maintenance easier and avoid bug scenarios where the icons are different because only one image was changed and not the other.

Add comment

  Country flag

biuquote
  • Comment
  • Preview
Loading