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:
3. Set the Custom Attributes for the Domain Property to reference the UITypeEditor class you have created.
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.