A Custom UITypeEditor for Activity Properties

As with many other technologies, the design time experience in Windows Workflow Foundation uses many of the same extensibility mechanisms found in other designers (such as the Windows Forms designer). One of those is the hability to provide custom type editors for properties by creating an UITypeEditor-derived class and then associating it with the property via the [Editor] attribute.

Here's a sample UITypeEditor that will present an OpenFileDialog to choose a file name as the property value:

//
// FileSelectorTypeEditor.cs
//
// Author:
//    Tomas Restrepo (tomasr@mvps.org)
//

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Drawing.Design;
using System.IO;
using System.Text;
using System.Windows.Forms;
using System.Windows.Forms.Design;

namespace Winterdom.Design.TypeEditors
{
   /// <summary>
   /// Customer UITypeEditor that pops up a
   /// file selector dialog
   /// </summary>
   public class FileSelectorTypeEditor : UITypeEditor
   {
      public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
      {
         if ( context == null || context.Instance == null )
            return base.GetEditStyle(context);
         return UITypeEditorEditStyle.Modal;
      }

      public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
      {
         IWindowsFormsEditorService editorService;

         if ( context == null || context.Instance == null || provider == null )
            return value;

         try
         {
            // get the editor service, just like in windows forms
            editorService = (IWindowsFormsEditorService)
               provider.GetService(typeof(IWindowsFormsEditorService));

            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Filter = "All Files (*.*)|*.*";
            dlg.CheckFileExists = true;

            string filename = (string)value;
            if ( !File.Exists(filename) )
               filename = null;
            dlg.FileName = filename;

            using ( dlg )
            {
               DialogResult res = dlg.ShowDialog();
               if ( res == DialogResult.OK )
               {
                  filename = dlg.FileName;
               }
            }
            return filename;

         } finally
         {
            editorService = null;
         }
      }
   } // class FileSelectorTypeEditor

} // namespace Winterdom.Design.TypeEditors

You can then easily associate it with a property like this:

[Editor(typeof(FileSelectorTypeEditor), typeof(UITypeEditor))]
public string Filename
{
   get { return _filename; }
   set { _filename = value; }
}

One thing to watch out for, though, is that at least with the July CTP of WinFX, WF will completely ignore your custom UITypeEditor if it is defined in the same assembly as the activity using it. Don't know why, but make sure you define it in a separate assembly you reference, and it should work OK.

10 comments

  1. I try this but it doesn’t work. I created a separate class library, compiled it to .NET assembly (Dll file) then reference it in windows Form application. The program runs without error, the dialog does not show.

    Please can you explain it again.

  2. Again, i converted it to VB.NET. May be because i used Overloads instead of overrides. Vb wont let me overrides it GetEditStyle and EditValue then i switched it to overloads method

    Can you comment on that please

    kenny

  3. Good Solution!
    Thanks

    ‘VB.NET Code

    Imports System
    Imports System.ComponentModel
    Imports System.Drawing.Design
    Imports System.IO
    Imports System.Windows.Forms
    Imports System.Windows.Forms.Design

    Public Class SelectorTypeFileDialog
    Public Class FileSelectorTypeEditor
    Inherits UITypeEditor

    Public Overloads Overrides Function GetEditStyle(ByVal context As ITypeDescriptorContext) As UITypeEditorEditStyle
    If context Is Nothing OrElse context.Instance Is Nothing Then
    Return MyBase.GetEditStyle(context)
    End If
    Return UITypeEditorEditStyle.Modal
    End Function

    Public Overloads Overrides Function EditValue(ByVal context As ITypeDescriptorContext, ByVal provider As IServiceProvider, ByVal value As Object) As Object
    Dim editorService As IWindowsFormsEditorService

    If context Is Nothing OrElse context.Instance Is Nothing OrElse provider Is Nothing Then
    Return value
    End If

    Try
    ‘ get the editor service, just like in windows forms
    editorService = DirectCast(provider.GetService(GetType(IWindowsFormsEditorService)), IWindowsFormsEditorService)

    Dim dlg As New OpenFileDialog()
    dlg.Filter = “All Files (*.*)|*.*”
    dlg.CheckFileExists = True

    Dim filename As String = DirectCast(value, String)
    If Not File.Exists(filename) Then
    filename = Nothing
    End If
    dlg.FileName = filename

    Using dlg
    Dim res As DialogResult = dlg.ShowDialog()
    If res = DialogResult.OK Then
    filename = dlg.FileName
    End If
    End Using

    Return filename
    Finally
    editorService = Nothing
    End Try
    End Function
    End Class
    End Class

  4. It strikes me that this is is a re-implementation of the .NET-supplied class FileNameEditor.

    The base class does exactly the same thing, and it has an “InitializeDialog” hook to allow programmers to do their own extensions, like this:

    —-

    Public Class ExecutableFileNameEditor
    Inherits System.Windows.Forms.Design.FileNameEditor

    Protected Overrides Sub InitializeDialog(ByVal openFileDialog As OpenFileDialog)
    openFileDialog.Title = “Select Executable File”
    openFileDialog.Filter = “Executable Files (*.exe)|*.exe”
    End Sub
    End Class

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>