Skip to main content
All docs
V23.2

How to: Register a Custom Mask

  • 8 minutes to read

You can add a custom mask if your scenario requires a mask that you cannot create with DevExpress mask placeholders, or you need to modify the mask input behavior. To add a custom mask, you need to create and register it. Note that this article does not explain how to create masks.

Registration allows you to resolve the following custom mask issues:

  • If users can invoke the Mask Settings dialog at runtime, this dialog does not display custom masks.
  • If an editor with a custom mask is used as a cell editor inside a data-aware control (for example, Data Grid), the editor’s mask does not match the mask inside standard control tools (for instance, filters). For example, when an in-place editor shows the date range “Date1 - Date2” mask, an exception is raised when users attempt to invoke the filter because the built-in DateTime column filter does not support this data type.

Follow the steps below to register a custom mask.

  1. In your custom MaskManager implementation, create a custom method that calls the static DevExpress.Data.Mask.MaskManager.RegisterMaskManagerType method. This custom method should be called on the application startup.

    MyDecimalMaskManager.Register();
    
    
    public class MyDecimalMaskManager : MaskManager {
        public static void Register() {
            string signature =
                typeof(MyDecimalMaskManager).Assembly.GetName().Name + ", " +
                typeof(MyDecimalMaskManager).FullName;
            RegisterMaskManagerType(signature,
                typeof(MyDecimalMaskManager), signature);
        }
        // ...
    }
    
  2. Decorate a custom MaskManager constructor with the Parameters attribute. This attribute allows you to set up default values for required mask properties. The first attribute parameter is the custom mask signature (type name), and the second is the public name of this custom mask in the Mask Settings dialog.

    Parameters attribute

    public class MyDecimalMaskManager : MaskManager {
        // ...
        [Parameters("MyApplication1, MyApplication1.MyDecimalMaskManager",
            "Double Precision Decimal", "allowNull", false)]
        public MyDecimalMaskManager(
            string mask,
            CultureInfo cultureInfo,
            bool allowNull)
            : this(new NumericMaskManager(mask, cultureInfo, allowNull)) {
        }
        // ...
    }
    

    Note that instead of setting default property values with this attribute, you can also set in inside the custom MaskManager constructor (the parameter is then considered as optional)…

    [Parameters("MyApplication1, MyApplication1.MyDecimalMaskManager",
        "Double Precision Decimal")]
    public MyDecimalMaskManager(
        string mask,
        CultureInfo cultureInfo,
        bool allowNull = false)
        : this(new NumericMaskManager(mask, cultureInfo, allowNull)) {
    }
    

    …or decorate these properties with the DefaultValue attribute.

    [Parameters("MyApplication1, MyApplication1.MyDecimalMaskManager",
        "Double Precision Decimal")]
    public MyDecimalMaskManager(
        string mask,
        CultureInfo cultureInfo,
        [DefaultValue(false)]
        bool allowNull)
        : this(new NumericMaskManager(mask, cultureInfo, allowNull)) {
    }
    
  3. Decorate properties or constructor parameters with the Parameter atrribute. This attribute allows you to:

    • Set an alias for the parameter. For example, the following code assigns the “culture” alias for the “cultureInfo” parameter.

      [Parameters("MyApplication1, MyApplication1.MyDecimalMaskManager",
          "Double Precision Decimal")]
      public MyDecimalMaskManager(
          string mask,
          [Parameter("culture", null)]
          CultureInfo cultureInfo,
          bool allowNull = false)
          : this(new NumericMaskManager(mask, cultureInfo, allowNull)) {
      }
      
    • Choose whether the corresponding setting should be visible in the Mask Settings dialog (the “Visibility” parameter), and assign its public name.

      Public name of a setting

      public MyDecimalMaskManager(
          string mask,
          [Parameter("culture", "Select a culture name", Visibility = ParameterVisibility.Advanced)]
          CultureInfo cultureInfo,
          bool allowNull = false)
          : this(new NumericMaskManager(mask, cultureInfo, allowNull)) {
      }
      
    • Assign a value converter for a property or constructor parameter. For example, the code below allows the “cultureInfo” constructor parameter to utilize the System.ComponentModel.CultureInfoConverter to transform string culture names (“en-US”, “ar-PS”, etc.) to CultureInfo objects and back.

      public MyDecimalMaskManager(
          string mask,
          [Parameter("culture", typeof(CultureInfoConverter), "Culture"]
          CultureInfo cultureInfo,
          bool allowNull = false)
          : this(new NumericMaskManager(mask, cultureInfo, allowNull)) {
      }
      

    You can use multiple Parameter attributes with different aliases for the same property. This allows you to choose aliases depending on input values.

    // constructor start
    [Parameter("cultureInfo")]
    [Parameter("culture", typeof(CultureInfoConverter), CultureDisplayName,
        Visibility = ParameterVisibility.Advanced)]
    CultureInfo managerCultureInfo
    // constructor end
    
  4. Editors limited to the specific data type show masks for this specific type only in the Mask Setting dialog. For instance, a SpinEdit can display only numbers, and hides other mask types (Date Time, Regex, etc.)

    Default spin edit masks

    Custom masks are also not available in the Mask Settings dialog. To display them, decorate your custom MaskManager with the Compatible attribute. The attribute parameter should reference the standard MaskManager type this editor uses (for instance, “NumericMaskManager” for a Spin Edit, or “DateTimeMaskManager” for a Date Edit).

    Custom spin edit masks

    [Compatible(typeof(NumericMaskManager))]
    public class MyDecimalMaskManager : MaskManager {
        // ...
    }
    
  5. Decorate alternative MaskManager constructors with the Ignore attribute to hide them from the dependency injector.

    [Ignore]
    public MyDecimalMaskManager(MaskManager _manager) {
        this.CoreManager = _manager;
        this.CoreManager.EditTextChanged += new EventHandler(Nested_EditTextChanged);
        this.CoreManager.EditTextChanging += new MaskChangingEventHandler(Nested_EditTextChanging);
        this.CoreManager.LocalEditAction += new CancelEventHandler(Nested_LocalEditAction);
    }
    

Apply a Custom Mask

To apply masks (standard and custom), call the MaskSettings.Configure method and specify its type. For custom masks, declare a custom MaskSettings.User descendant.

public abstract class CustomMaskSettings : MaskSettings.User {
    public class Decimal : MaskSettingsWithCulture {
        protected override Type GetMaskManagerType() {
            return typeof(MyDecimalMaskManager);
        }
    }
}

// apply the custom mask
var settings = spinEdit.MaskSettings.Configure<CustomMaskSettings.Decimal>();
settings.MaskExpression = "#################0\\.00";

This routine allows you to create API for custom mask properties. For example, the code below illustrates how to declare and use the “Precision” property that allows users to set the number of digits after the separator.

Note

This code disables the standard MaskExpression setting – it is assigned inside the MaskManager constructor depending on the entered Precision value.

public abstract class CustomMaskSettings : MaskSettings.User {
    public class Decimal : MaskSettingsWithCulture {
        protected override Type GetMaskManagerType() {
            return typeof(MyDecimalMaskManager);
        }
        public int Precision {
            get { return GetValue("alias", 2); }
            set { SetValue("alias", value); }
        }
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new string MaskExpression {
            get { return base.MaskExpression; }
            set { }
        }
    }
}

// usage
var settings = spinEdit.MaskSettings.Configure<CustomMaskSettings.Decimal>();
settings.Precision = 3;

In the MaskManager constructor, you need to declare a parameter that corresponds to your custom property. The Parameter attribute specifies the injection point and allows you to set the property alias.

[Compatible(typeof(NumericMaskManager))]
public class MyDecimalMaskManager : MaskManager {
    // ...
    [Parameters("MyApplication, MyApplication.MyDecimalMaskManager", "Decimal (Variable Precision)")]
    public MyDecimalMaskManager(
        [Parameter("culture", typeof(CultureInfoConverter), "Culture (name)", Visibility = ParameterVisibility.Advanced)]
        CultureInfo cultureInfo,
        [Parameter("alias", "Set Precision")]
        int precision=2)
        : this(new NumericMaskManager("#####0\\." + new string('0', precision), cultureInfo, false)) {
    }
}

The figure below illustrates the Mask Settings dialog for this custom mask.

Custom mask in dialog

Demo

The DevExpress Demo Center includes the “Date Ranges (Custom Mask)” module that demonstrates how to register the custom “Date Range” mask.

Date Range mask

Run Demo