Intercepting keys in custom UITypeEditor's

The Implementation

In order to explore the implementation choices, let's build a ResourceImageEditor type editor that allows for picking an image file from the file system (just like the built-in ImageEditor class) or picking an image resource from an assembly's manifest. With regards to user experience, the ResourceImageEditor should behave like the built-in type editors. Here are our requirements in a nutshell:

  1. When the user selects a property in the property grid, the grid should display a down-arrow button indicating that the property will be edited with a drop-down UI.
  2. When the down-arrow button is clicked, a list of all image resources from the current assembly should be displayed.
  3. When the user selects an image resource item, the image will be loaded from the assembly.
  4. To allow for selecting an image file, the last item in the drop-down list will be labeled as "Browse...". When the user clicks the "Browse..." item, the "classic" open file dialog will be displayed and the user will be able to pick an image file from the file system.
  5. The drop-down list will allow the user to select an item by single-clicking it with the mouse, or by using the arrow keys to highlight an item and pressing the ENTER key to actually select it. The drop-down selection will be also accepted by clicking off of the list. The drop-down selection will be canceled by pressing the ESC key.
The ResourceImageEditor is a type editor so it should derive (directly or indirectly) from the System.Drawing.Design.UITypeEditor class. I've decided to inherit from the built-in System.Drawing.Design.ImageEditor , because it already implements the image file selection functionality specified in the fourth requirement above. That is, the ImageEditor.EditValue implementation displays a file open dialog allowing the user to select an image file from the file system. Invoking this functionality from within my derived class is then a simple call to MyBase.EditValue .

In order satisfy the first requirement (displaying the down-arrow button in the property grid), I've had to override the GetEditStyle method to return the appropriate constant from the UITypeEditorEditStyle enumeration:

Public Overloads Overrides Function GetEditStyle( _
  ByVal context As ITypeDescriptorContext) As UITypeEditorEditStyle
   
  Return UITypeEditorEditStyle.DropDown
End Function

To display the list of image resources, I've had to enumerate all resources in a given assembly and display only the image resources in the list. To keep things simple, I've decided to employ a simple convention - when a resource name ends with a valid image file extension (.bmp, .jpg, .gif...), it is considered an image resource and it will be included in the drop-down list. The collection of image resource names is used to populate the drop-down ListBox control as described later.

Initially, the assembly that is enumerated for image resources is the one containing the ResourceImageEditor class. However, it can be changed setting the ResourceImageEditor.ResourceAssembly property to any valid System.Reflection.Assembly reference.

When the user selects an image resource name in the list box, the image should be loaded from the given assembly's manifest. This is implemented within the LoadResourceImage method:

Private Function LoadResourceImage(ByVal resourceName As String) As Image
  Debug.Assert(Not resourceName Is Nothing)
  Dim ImageStream As System.IO.Stream = _
    Me.ResourceAssembly.GetManifestResourceStream(resourceName)
  Return System.Drawing.Bitmap.FromStream(ImageStream)
End Function

The drop-down user interface is implemented by dynamically creating and populating a ListBox control inside the overridden EditValue method. The editor also handles the Click and KeyDown events generated by the ListBox , which is necessary to intercept the ENTER and ESC keys. Here is pseudocode illustrating the logic inside the EditValue method:

Public Overloads Overrides Function EditValue(...)
  ' Store the context information for use in the drop-down ListBox event handlers.
  ' Create and fill the ListBox with the names of the available image resources.
  ' Add our special "Browse..." item.
  ' Wire the ListBox events.
  ' Display the ListBox in a drop-down window.
End Function

That's it.

You might also like...

Comments

About the author

Palo Mraz

Palo Mraz United States

I live in Slovakia with my wife, two sons (fulltime), one daughter (occasionally) and a dog. I've been doing Microsoft Windows development since 1988; primarily in VB. I'm a big fan of the MS .N...

Interested in writing for us? Find out more.

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“Perl - The only language that looks the same before and after RSA encryption.” - Keith Bostic