DSL Tools #7 - Custom Property Editors (Ellipsis)

 

In this previous post I described how to create a custom property editor to show a list box that the user can select from to set the value of a domain property.

The other day I had a pretty similar requirement but which implementation is slightly simpler but also very useful.

I wanted to have a property in my domain model where the user basically provides a file name:

Click to see large image

The next logical step was that I wanted to let the user select that file name using the standard open file dialog:

Click to see large image

Click to see large image

This is pretty simple and it can be achieved using a custom property editor.

1. Create the custom UITypeEditor class

This class should derive from System.Drawing.Design.UITypeEditor and override the GetEditStyle and EditValue methods.

In the GetEditStyle we specify the editor style has UITypeEditorEditStyle.Modal. This will put a pretty ellipsis button in the properties window.

Here's the basic code:

   1: using System;
   2: using System.Drawing.Design;
   3: using System.ComponentModel;
   4: using System.Windows.Forms;
   5: using System.Windows.Forms.Design;
   6: using System.Security;
   7: using System.Security.Permissions;
   8:  
   9: namespace Primavera.Athena.Models.Entities
  10: {
  11:     /// <summary>
  12:     /// Implements the ModelDefinitionFile domain attribute property 
  13:     /// editor.
  14:     /// </summary>
  15:     public class ModelDefinitionFileTypeEditor : UITypeEditor
  16:     {
  17:         #region Public Methods
  18:  
  19:         /// <summary>
  20:         /// Gets the editor style used by the <see cref="M:System.Drawing.Design.UITypeEditor.EditValue(System.IServiceProvider,System.Object)"></see> method.
  21:         /// </summary>
  22:         /// <param name="context">An <see cref="T:System.ComponentModel.ITypeDescriptorContext"></see> that can be used to gain additional context information.</param>
  23:         /// <returns>
  24:         /// A <see cref="T:System.Drawing.Design.UITypeEditorEditStyle"></see> value that indicates the style of editor used by the <see cref="M:System.Drawing.Design.UITypeEditor.EditValue(System.IServiceProvider,System.Object)"></see> method. If the <see cref="T:System.Drawing.Design.UITypeEditor"></see> does not support this method, then <see cref="M:System.Drawing.Design.UITypeEditor.GetEditStyle"></see> will return <see cref="F:System.Drawing.Design.UITypeEditorEditStyle.None"></see>.
  25:         /// </returns>
  26:         [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
  27:         public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
  28:         {
  29:             // Return value
  30:  
  31:             if (context != null)
  32:             {
  33:                 return UITypeEditorEditStyle.Modal;
  34:             }
  35:  
  36:             // Default behavior
  37:  
  38:             return base.GetEditStyle(context);
  39:         }
  40:  
  41:         /// <summary>
  42:         /// Edits the specified object's value using the editor style indicated by the <see cref="M:System.Drawing.Design.UITypeEditor.GetEditStyle"></see> method.
  43:         /// </summary>
  44:         /// <param name="context">An <see cref="T:System.ComponentModel.ITypeDescriptorContext"></see> that can be used to gain additional context information.</param>
  45:         /// <param name="provider">An <see cref="T:System.IServiceProvider"></see> that this editor can use to obtain services.</param>
  46:         /// <param name="value">The object to edit.</param>
  47:         /// <returns>
  48:         /// The new value of the object. If the value of the object has not changed, this should return the same object it was passed.
  49:         /// </returns>
  50:         [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
  51:         public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
  52:         {
  53:             // Default behavior
  54:  
  55:             return base.EditValue(context, provider, value);
  56:         }
  57:  
  58:         #endregion
  59:     }
  60: }

2. Define the custom attribute for the domain property

In the DSL designer, select the property where this behavior is required and edit its Custom Attributes.

Define a new one with the following properties:

  • Name: System.ComponentModel.Editor
  • Parameter: typeof(MyModel.ModelDefinitionFileTypeEditor), typeof(System.Drawing.Design.UITypeEditor)

Notice that you should replace MyModel.ModelDefinitionFileTypeEditor with the full name of the your custom type editor.

3. Implement the logic to leverage the open file dialog

The next step is to implement the logic required to open the dialog when the user selects the ellipsis button.

This is done in the EditValue method.

Notice that this code is much simpler than the one I used to implement a combo box. We just have to process the previous value (received in parameter value) and return the new value.

   1: /// <summary>
   2: /// Edits the specified object's value using the editor style indicated by the <see cref="M:System.Drawing.Design.UITypeEditor.GetEditStyle"></see> method.
   3: /// </summary>
   4: /// <param name="context">An <see cref="T:System.ComponentModel.ITypeDescriptorContext"></see> that can be used to gain additional context information.</param>
   5: /// <param name="provider">An <see cref="T:System.IServiceProvider"></see> that this editor can use to obtain services.</param>
   6: /// <param name="value">The object to edit.</param>
   7: /// <returns>
   8: /// The new value of the object. If the value of the object has not changed, this should return the same object it was passed.
   9: /// </returns>
  10: [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
  11: public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
  12: {
  13:     // Default behavior
  14:  
  15:     if ((context == null) || (provider == null) || (context.Instance == null))
  16:     {
  17:         return base.EditValue(context, provider, value);
  18:     }
  19:  
  20:     // Get current value
  21:  
  22:     string fileName = (string)value;
  23:  
  24:     // Show the editor
  25:  
  26:     using (OpenFileDialog dialog = new OpenFileDialog())
  27:     {
  28:         // Setup dialog
  29:  
  30:         dialog.AddExtension = true;
  31:         dialog.CheckFileExists = true;
  32:         dialog.CheckPathExists = true;
  33:         dialog.DefaultExt = "xml";
  34:         dialog.FileName = fileName;
  35:         dialog.Filter = Properties.Resources.RES_ModelDefinitionFileDialogFilter;
  36:         dialog.Multiselect = false;
  37:         dialog.Title = Properties.Resources.RES_SelectModelDefinitionFile;
  38:         if (dialog.ShowDialog() == DialogResult.OK)
  39:         {
  40:             return dialog.FileName;
  41:         }
  42:     }
  43:  
  44:     // Default behavior
  45:  
  46:     return base.EditValue(context, provider, value);
  47: }

4. Transform all templates

Go ahead and transform all the templates in the DSL solution. It should work just fine.

Published 20 December 07 06:37 by hgr
Filed under: ,

Comments

# Hugo Ribeiro said on July 15, 2008 6:43 PM:

Since I've been doing a number of posts on the DSL Tools, I thought it would be helpful to have a list

Anonymous comments are disabled