How to Create a Custom Property Editor for a Domain Model Element Property

by Jim Lavin

Sometimes when defining a property for a domain model element you may need to use a complex type that has more than one property or can’t easily be displayed using a single text field or drop down in the property editor. A good example might be a class that holds a list of strings for a GUI interface or a Rich Text editor for a custom text field required by your framework.

To resolve this you can create a custom editor and hook it into your domain model that will provide a proper user interface to specify information for your property.

There are three steps you need to take in order to wire your domain property to display a custom editor:

1. Create a class derived from System.Drawing.Design.UITypeEditor that will launch the custom dialog box as below:

using System;
using System.Collections.Generic;
using System.Text;
// Need to add a reference to System.Drawing DLL.
using System.Drawing.Design;
using System.Security.Permissions;
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Design;
namespace XXX.UIProcessDesigner.UIEditors
{
    // FxCop rule: must have same security demands as parent class
    [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust"),
    PermissionSet(SecurityAction.InheritanceDemand, Name = "FullTrust")]
    public class FormPromptUITypeEditor :
    System.Drawing.Design.UITypeEditor
    {
        /// <summary>
        /// Overridden to specify that our editor is a modal form
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public override UITypeEditorEditStyle
        GetEditStyle(System.ComponentModel.ITypeDescriptorContext context)
        {
            return UITypeEditorEditStyle.Modal;
        }
        /// <summary>
        /// Called by VS whenever the user clicks on the ellipsis in the 
        /// properties window for a property to which this editor is linked.
        /// </summary>
        /// <param name="context"></param>
        /// <param name="provider"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public override object EditValue(
            System.ComponentModel.ITypeDescriptorContext context,
            IServiceProvider provider,
            object value)
        {
            // Get a reference to the underlying property element
            ElementPropertyDescriptor descriptor = context.PropertyDescriptor as
            	ElementPropertyDescriptor;
            ModelElement underlyingModelElent = descriptor.ModelElement;
            // context.Instance also returns a model element, but this will either
            // be the shape representing the underlying element (if you selected
            // the element via the design surface), or the underlying element 
            // itself (if you selected the element via the model explorer)
            ModelElement element = context.Instance as ModelElement;
            FormPromptUITypeEditorForm theForm = new FormPromptUITypeEditorForm();
            theForm.Value = (string)value;
            if (theForm.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                value = theForm.Value;
            }
            return value;
        }
    }
}

2. Create a Windows Form dialog that will be displayed when the editor is invoked, such as the one below:

samplewindowsform_2

3. Set the Custom Attributes for the Domain Property to reference the UITypeEditor class you have created.

samplepropertiesform_2

The text is as follows:

[System.ComponentModel.Editor(typeof(XXX.UIProcessDesigner.UIEditors.FormActionTypeUITypeEditor),typeof(System.Drawing.Design.UITypeEditor))]

The bold faced text is the full namespace of your class that derives from UITypeEditor.

I normally store all code that I add to a DSL Designer in various folders such as; CustomCode, UIEditors, Validators, etc. That way it is easy to find when I am trying to reference it.

Also, you can debug the UITypeEditor and Dialog by setting breakpoints in the code before you start debugging.

Leave a Reply

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