Home > C#, WinRT > FilteredTextBoxBehavior for Windows 8.1 Store apps

FilteredTextBoxBehavior for Windows 8.1 Store apps

24/01/2014

The Windows 8.1 Behavoir SDK contains behaviors for the most common scenarios. However, we may need to create new ones to fulfill our requirements. In this case, we can define a class that inherits from the IBehavior interface and implements our custom rules.

For example, the following class defines a behavior that allows to specify a regular expression to restrict input in a TextBox:

public class FilteredTextBoxBehavior : DependencyObject, IBehavior
{
    private string lastValidText;

    public DependencyObject AssociatedObject { get; private set; }

    public static readonly DependencyProperty ExpressionProperty =
        DependencyProperty.Register("Expression",
        typeof(string),
        typeof(FilteredTextBoxBehavior),
        new PropertyMetadata(null));

    public string Expression
    {
        get
        {
            return (string)base.GetValue(ExpressionProperty);
        }
        set
        {
            base.SetValue(ExpressionProperty, value);
        }
    }

    public void Attach(DependencyObject associatedObject)
    {
        var txt = associatedObject as TextBox;
        if (txt == null)
            throw new ArgumentException(
                "FilteredTextBoxBehavior can be attached only to TextBox");

        AssociatedObject = associatedObject;

        lastValidText = txt.Text;
        txt.TextChanged += OnTextChanged;
    }

    private void OnTextChanged(object sender, TextChangedEventArgs e)
    {
        var txt = AssociatedObject as TextBox;
        if (txt != null && !string.IsNullOrWhiteSpace(Expression))
        {
            if (Regex.IsMatch(txt.Text, Expression))
            {
                // The text matches the regular expression.
                lastValidText = txt.Text;
            }
            else
            {
                // The text doesn't match the regular expression.
                // Restore the last valid value.
                var caretPosition = txt.SelectionStart;
                txt.Text = lastValidText;
                txt.SelectionStart = caretPosition - 1;
            }
        }
    }

    public void Detach()
    {
        var txt = AssociatedObject as TextBox;
        if (txt != null)
            txt.TextChanged -= this.OnTextChanged;
    }
}

The Attach and Detach methods are defined on the IBehavior interface. As the name implies, the first one is invoked when the behavior is attached to the specified object. We check if it is a TextBox and, in this case, we register on the TextChanged event. In its handler, we check if the text matches the regular expression contained in the Expression dependency property (line 43). If it isn’t the case, we restore the last valid value.

Now we can try the new behavior in our XAML pages, like the one that follows:

<Page
    ...
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:i="using:Microsoft.Xaml.Interactivity"
    xmlns:core="using:Microsoft.Xaml.Interactions.Core">

    ...
    <TextBox Height="35" Width="500">
        <i:Interaction.Behaviors>
            <local:FilteredTextBoxBehavior Expression="^[a-zA-Z\s]*$" />
        </i:Interaction.Behaviors>
    </TextBox>
    ...

The definition ^[a-zA-Z\s]*$ at line 10 restricts the allowed characters to only uppercase and lowercase letters, plus the whitespace.

As our behavior accepts a standard regular expression, we can use it also in some more complex scenarios. For example, the expression ^(\+|-)?[0-9]*(\.)?[0-9]*$ allows only integer or decimal numbers, with or without the initial sign.

Categories: C#, WinRT
Comments are closed.
%d bloggers like this: