Masked Silverlight TextBox for Swedish National Identification Number (Personnummer)

In our upcoming Silverlight 4 project there’s a need for a textbox with a mask for entering a Swedish national identification number (personnummer) with either 10 or 12 digits, in the form of yyyymmdd-nnnn. It’s quite simple, I just want to make sure only digits are entered and that the dash (-) is placed automatically and a few other small things that I’d like to tweak.

As far as I can see (correct me if I’m wrong here) there’s no mask feature in SL4 (yet), so I’m simply going to inherit and extend the built in TextBox. Validation of the number is done in the viewmodel instead of built into the control. See upcoming blogpost for that.

So, enough talk already, hope it can be of use:

public class PersonnummerTextBox : TextBox
{
    public bool TwelveDigits { get; set; }

    private int _leftPart;
    private Key _lastKey;

    public PersonnummerTextBox()
    {
        TextChanged += OnTextChanged;
        Loaded += OnLoaded;
    }

    private void OnLoaded(object sender, RoutedEventArgs e)
    {
        _leftPart = TwelveDigits ? 8 : 6;
    }

    /// <summary>
    /// Only allow digits and tab, no shifts or ctrl
    /// </summary>
    /// <param name="e"></param>
    protected override void OnKeyDown(KeyEventArgs e)
    {
        _lastKey = e.Key;   //used in OnTextChanged to handle Del key

        base.OnKeyDown(e);

        if (((e.Key >= Key.NumPad0 && e.Key <= Key.NumPad9) ||
            (e.Key >= Key.D0 && e.Key <= Key.D9) ||
            e.Key == Key.Tab) &&    //so that we can TAB out from the control ;)
            (Keyboard.Modifiers & ModifierKeys.Shift) == 0 &&
            (Keyboard.Modifiers & ModifierKeys.Control) == 0)
        {
            e.Handled = false;
            return;
        }

        e.Handled = true;
    }

    /// <summary>
    /// Make sure the dash (-) is placed on the correct place automatically
    /// either as yyyymmdd-nnnn or yymmdd-nnnn
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void OnTextChanged(object sender, TextChangedEventArgs e)
    {
        var leftPartPlusDash = (_leftPart + 1);
        var cursorPosition = SelectionStart;
        var strippedText = Text.Replace("-", "");

        if (strippedText.Length > _leftPart)
        {
            //move the cursor after the dash
            if (strippedText.Length == leftPartPlusDash &&
                cursorPosition == leftPartPlusDash &&
                _lastKey != Key.Delete)
                cursorPosition = (_leftPart + 2);

            //put a dash in the right place
            Text = string.Format("{0}-{1}",
                strippedText.Substring(0, _leftPart),
                strippedText.Substring(_leftPart, Math.Min(4, strippedText.Length - _leftPart)));
        }
        else
            Text = strippedText;

        //move cursor to the wanted position
        SelectionStart = cursorPosition;
    }
}

No Comments