Click here to Skip to main content
15,896,727 members
Articles / Desktop Programming / WPF

WPF.JoshSmith

Rate me:
Please Sign up or sign in to vote.
4.99/5 (51 votes)
13 Jul 2008CPOL5 min read 391.5K   4.8K   263  
A free library of controls and utility classes for use in WPF applications.
// Copyright (C) Josh Smith - September 2006
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;

namespace WPF.JoshSmith.Controls.Validation
{
    /// <summary>
    /// This static class provides attached properties which supply 
    /// validation of the text in a TextBox, using regular expressions.
    /// </summary>
    /// <remarks>
    /// Documentation: http://www.codeproject.com/KB/WPF/RegexValidationInWPF.aspx
    /// </remarks>
    public static class RegexValidator
    {
        #region Static Constructor

        static RegexValidator()
        {
            RegexTextProperty = DependencyProperty.RegisterAttached(
                "RegexText",
                typeof(string),
                typeof(RegexValidator),
                new UIPropertyMetadata(null, OnAttachedPropertyChanged));

            ErrorMessageProperty = DependencyProperty.RegisterAttached(
                "ErrorMessage",
                typeof(string),
                typeof(RegexValidator),
                new UIPropertyMetadata(null, OnAttachedPropertyChanged));
        }

        #endregion // Static Constructor

        #region Attached Properties

        #region ErrorMessage

        /// <summary>
        /// Identifies the RegexValidator's ErrorMessage attached property.  
        /// This field is read-only.
        /// </summary>
        public static readonly DependencyProperty ErrorMessageProperty;

        /// <summary>
        /// Returns the error message used when validation fails for the
        /// specified TextBox.
        /// </summary>
        /// <param name="textBox">The TextBox whose error message is returned.</param>
        public static string GetErrorMessage(TextBox textBox)
        {
            return textBox.GetValue(ErrorMessageProperty) as string;
        }

        /// <summary>
        /// Sets the error message used when validation fails for the 
        /// specified TextBox.
        /// </summary>
        /// <param name="textBox">The TextBox being validated.</param>
        /// <param name="value">The error message.</param>
        public static void SetErrorMessage(TextBox textBox, string value)
        {
            textBox.SetValue(ErrorMessageProperty, value);
        }

        #endregion // ErrorMessage

        #region RegexText

        /// <summary>
        /// Identifies the RegexValidator's RegexText attached property.  
        /// This field is read-only.
        /// </summary>
        public static readonly DependencyProperty RegexTextProperty;

        /// <summary>
        /// Returns the regular expression used to validate the specified TextBox.
        /// </summary>
        /// <param name="textBox">The TextBox whose regular expression is returned.</param>
        public static string GetRegexText(TextBox textBox)
        {
            return textBox.GetValue(RegexTextProperty) as string;
        }

        /// <summary>
        /// Sets the regular expression used to validate the 
        /// specified TextBox.
        /// </summary>
        /// <param name="textBox">The TextBox being validated.</param>
        /// <param name="value">The regular expression.</param>
        public static void SetRegexText(TextBox textBox, string value)
        {
            textBox.SetValue(RegexTextProperty, value);
        }

        #endregion // RegexText

        #endregion // Attached Properties

        #region Event Handling Methods

        #region OnAttachedPropertyChanged

        /// <summary>
        /// Invoked whenever an attached property of the 
        /// RegexValidator is modified for a TextBox.
        /// </summary>
        /// <param name="depObj">A TextBox.</param>
        /// <param name="e"></param>
        static void OnAttachedPropertyChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e)
        {
            TextBox textBox = depObj as TextBox;
            if (textBox == null)
                throw new InvalidOperationException(
                    "The RegexValidator can only be used with a TextBox.");

            VerifyRegexValidationRule(textBox);
        }

        #endregion // OnAttachedPropertyChanged

        #endregion // Event Handling Methods

        #region Private Helpers

        #region GetRegexValidationRuleForTextBox

        /// <summary>
        /// Returns a RegexValidationRule to be used for validating the specified TextBox.
        /// If the TextBox is not yet initialized, this method returns null.
        /// </summary>
        static RegexValidationRule GetRegexValidationRuleForTextBox(TextBox textBox)
        {
            if (!textBox.IsInitialized)
            {
                // If the TextBox.Text property is bound, but the TextBox is not yet
                // initialized, the property's binding can be null.  In that situation,
                // hook its Initialized event and verify the validation rule again when 
                // that event fires.  At that point in time, the Text property's binding
                // will be non-null.
                EventHandler callback = null;
                callback = delegate
                {
                    textBox.Initialized -= callback;
                    VerifyRegexValidationRule(textBox);
                };
                textBox.Initialized += callback;
                return null;
            }

            // Get the binding expression associated with the TextBox's Text property.
            BindingExpression expression = textBox.GetBindingExpression(TextBox.TextProperty);
            if (expression == null)
                throw new InvalidOperationException(
                    "The TextBox's Text property must be bound for the RegexValidator to validate it.");

            // Get the binding which owns the binding expression.
            Binding binding = expression.ParentBinding;
            if (binding == null)
                throw new ApplicationException(
                    "Unexpected situation: the TextBox.Text binding expression has no parent binding.");

            // Look for an existing instance of the RegexValidationRule class in the
            // binding.  If there is more than one instance in the ValidationRules
            // then throw an exception because we don't know which one to modify.
            RegexValidationRule regexRule = null;
            foreach (ValidationRule rule in binding.ValidationRules)
            {
                if (rule is RegexValidationRule)
                {
                    if (regexRule == null)
                        regexRule = rule as RegexValidationRule;
                    else
                        throw new InvalidOperationException(
                            "There should not be more than one RegexValidationRule in a Binding's ValidationRules.");
                }
            }

            // If the TextBox.Text property's binding does not yet have an 
            // instance of RegexValidationRule in its ValidationRules,
            // add an instance now and return it.
            if (regexRule == null)
            {
                regexRule = new RegexValidationRule();
                binding.ValidationRules.Add(regexRule);
            }

            return regexRule;
        }

        #endregion // GetRegexValidationRuleForTextBox

        #region VerifyRegexValidationRule

        /// <summary>
        /// Creates or modifies the RegexValidationRule in the TextBox's Text property binding
        /// to use the current values of the attached properties exposed by this class.
        /// </summary>
        /// <param name="textBox">The TextBox being validated.</param>
        static void VerifyRegexValidationRule(TextBox textBox)
        {
            RegexValidationRule regexRule = GetRegexValidationRuleForTextBox(textBox);
            if (regexRule != null)
            {
                regexRule.RegexText = textBox.GetValue(RegexValidator.RegexTextProperty) as string;
                regexRule.ErrorMessage = textBox.GetValue(RegexValidator.ErrorMessageProperty) as string;
            }
        }

        #endregion // VerifyRegexValidationRule

        #endregion // Private Helpers
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United States United States
Josh creates software, for iOS and Windows.

He works at Black Pixel as a Senior Developer.

Read his iOS Programming for .NET Developers[^] book to learn how to write iPhone and iPad apps by leveraging your existing .NET skills.

Use his Master WPF[^] app on your iPhone to sharpen your WPF skills on the go.

Check out his Advanced MVVM[^] book.

Visit his WPF blog[^] or stop by his iOS blog[^].

See his website Josh Smith Digital[^].

Comments and Discussions