How to override MaxLength, Mask, PromptChar properties of maskedTextBox

1.4k views Asked by At

I created a class that I called MaskedHexTextBox which inherits from MaskedTetxBox to make it accept only HEX values. Anyway, I need to do the following:

  • Give PromptChar a default value of '0' in MaskedHexTextBox, and still be able to change it in the form design
  • Give Mask a default value of "\0xAAAA", and still be able to change it in the form design as well
  • Use Mask.Length as the default value of MaxLength, I need to use in some calcs, and if I change the Mask after I place the control on the form, I still get the correct Mask length

In general, how can I set a default values for Mask and PromtChar, is there a specific event that I can use to give these properties default values once the control is placed on the form?

I used the class constructor to do this:

    public MaskedHexTextBox()
    {
        Mask = "\\0xAAAA";
        PromptChar = '0';
        MaxLength = Mask.Replace("\\", string.Empty).Length;
    }

in the Form_load event, I still see that the value for MaxLength is 32767

    private void Form1_Load(object sender, EventArgs e)
    {
        MessageBox.Show(maskedHexTextBox1.MaxLength.ToString());
    }

Another issue, suppose that MaxLength was correct, how can I ensure that if the mask is changed from the form design that MaxLength is updated?

1

There are 1 answers

9
Rubidium 37 On BEST ANSWER

About Mask and PromptChar properties, if you want the designer to use your custom default values instead of the base ones, then you have to associate them through some helper class (like a Designer that overrides PreFilterProperties) or to hide the base properties declaring new ones with the same names, like:

[Localizable(true), RefreshProperties(RefreshProperties.Repaint)]
[DefaultValue('0')]
public new char PromptChar
{
    get { return base.PromptChar; }
    set { base.PromptChar = value; }
}

[MergableProperty(false), Localizable(true), RefreshProperties(RefreshProperties.Repaint)]
[Editor("System.Windows.Forms.Design.MaskPropertyEditor, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
[DefaultValue("\\0xAAAA")]
public new string Mask
{
    get { return base.Mask; }
    set { base.Mask = value; }
}

For the MaxLength property, theoretically you should override it, but the class MaskedTextBox provides an empty set accessor that never change the underlying TextBoxBase.maxLength field, so you cannot change through the base property.


You can however try through Reflection, eventually improving your Mask property:

[MergableProperty(false), Localizable(true), RefreshProperties(RefreshProperties.Repaint)]
[Editor("System.Windows.Forms.Design.MaskPropertyEditor, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
[DefaultValue("\\0xAAAA")]
public new string Mask
{
    get { return base.Mask; }
    set
    {
        if (base.Mask != value)
        {
            base.Mask = value;
            //FIX_20141127
            //MaxLengthProperty_Set.Invoke(this, new object[] { Mask.Replace("\\", string.Empty).Length });
            SetMaxLength(Mask.Replace("\\", string.Empty).Length);
        }
    }
}

//FIX_20141127
private void SetMaxLength(int value)
{
    if (IsHandleCreated)
    {
        MaxLengthProperty_Set.Invoke(this, new object[] { value});
        MaxLengthField.SetValue(this, value);
    }
}

private static readonly PropertyInfo MaxLengthProperty = typeof(TextBoxBase).GetProperty("MaxLength", BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);
private static readonly MethodInfo MaxLengthProperty_Set = MaxLengthProperty.GetSetMethod();
//FIX_20141127
private static readonly FieldInfo MaxLengthField = typeof(TextBoxBase).GetField("maxLength", BindingFlags.Instance | BindingFlags.NonPublic);

If you also want the MaxLength property to be visible from the designer, you can add:

[Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[ReadOnly(true)]
public override int MaxLength
{
    get { return base.MaxLength; }
    set { }
}

UPDATE_20141127 (A) To address the fact that TextBoxBase.MaxLength seems to not change, you can override OnHandleCreated:

//FIX_20141127
protected override void OnHandleCreated(EventArgs e)
{
    base.OnHandleCreated(e);

    SetMaxLength(Mask.Replace("\\", string.Empty).Length);
}

UPDATE_20141127 (B) At the following link you can find my (working) test project, containing a minimal MaskedTextBox derived class and a form to display it, along with a button to change the Mask and check MaxLength value. Test project

At this other link you can find an already compiled exe for the previous project. Test exe


Regards, Daniele.