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

A framework for comprehensive validation of user input

Rate me:
Please Sign up or sign in to vote.
4.70/5 (8 votes)
19 Jun 2012CPOL28 min read 31.3K   523   18  
Validation of input made as easy as possible for Windows.Forms, WPF, console-applications or any other purposes
// Copyright (c) 2010 - 2012, Andreas Ganzer. All Rights reserved.

using System;
using System.Diagnostics;
using System.Globalization;
using System.Windows.Controls;
using System.Windows.Data;
using Ganzer.Validation;

namespace Ganzer.Wpf.Validation
{
	//############################################################################
	/// <summary>
	/// The ValidatorValidationRule class defines a validation rule that uses
	/// a <see cref="Validator"/> object for input validation.
	/// </summary>
	/// 
	public class ValidatorValidationRule : ValidationRule
	{
		#region properties

		private Validator _validator;

		/// <summary>
		/// Gets or sets the validator to use.
		/// </summary>
		/// 
		/// <returns>The validator to use or <c>null</c> if no validator is set.
		///   </returns>
		///   
		/// <remarks>
		/// This property can be set in XAML but cannot be filled by a data binding.
		/// </remarks>
		/// 
		public Validator Validator
		{
			get
			{
				return _validator;
			}
			set
			{
				_validator = value;
			}
		}

		private string _propertyName;

		/// <summary>
		/// Gets or sets the name of the property to validate.
		/// </summary>
		/// 
		/// <returns>The name of the property to validate or <c>null</c> if no
		///   name is set.</returns>
		/// 
		/// <remarks>
		/// <para>This is necessary to validate a binding group. This property is
		/// ignored if this validation rule is not defined within a binding group.
		/// </para>
		/// <para>This property can be set in XAML but cannot be filled by a data
		/// binding.</para>
		/// </remarks>
		/// 
		public string PropertyName
		{
			get
			{
				return _propertyName;
			}
			set
			{
				_propertyName = value;
			}
		}

		private int _itemIndex;

		/// <summary>
		/// Gets or sets the item index of the binding group data to validate.
		/// </summary>
		/// 
		/// <returns>The item index of the binding group data.</returns>
		/// 
		/// <exception cref="ArgumentException">The value to set is less than zero.
		///   </exception>
		/// 
		/// <remarks>
		/// <para>This is necessary to validate a binding group. This property is
		/// ignored if this validation rule is not defined within a binding group.
		/// </para>
		/// <para>This property can be set in XAML but cannot be filled by a data
		/// binding.</para>
		/// </remarks>
		/// 
		public int ItemIndex
		{
			get
			{
				return _itemIndex;
			}
			set
			{
				Debug.Assert(value >= 0);

				if( value < 0 )
					throw new ArgumentException("The value to set must not be less than zero.", "value");

				_itemIndex = value;
			}
		}

		#endregion

		#region ctor/dtor

		/// <summary>
		/// Creates an empty rule.
		/// </summary>
		/// 
		public ValidatorValidationRule()
		{
		}

		/// <summary>
		/// Initializes this object with the specified arguments.
		/// </summary>
		/// 
		/// <param name="validator">The validator to use.</param>
		/// 
		public ValidatorValidationRule( Validator validator )
		{
			_validator = validator;
		}

		#endregion

		#region methods

		/// <summary>
		/// This is called by the framework to validate the specifed value.
		/// </summary>
		/// 
		/// <param name="value">The value to validate.</param>
		/// <param name="cultureInfo">The culture to use.</param>
		/// 
		/// <returns><see cref="ValidationResult.ValidResult"/> if <paramref name="value"/>
		///   is valid or <see cref="Validator"/> is <c>null</c>; otherwise, another
		///   <see cref="ValidationResult"/> instance is returned.</returns>
		/// 
		public override ValidationResult Validate( object value, CultureInfo cultureInfo )
		{
			if( _validator != null )
			{
				BindingGroup group = value as BindingGroup;

				if( group != null )
					return ValidateGroup(group, cultureInfo);

				return ValidateInput(value, cultureInfo);
			}

			return ValidationResult.ValidResult;
		}

		/// <summary>
		/// Validates the specifed value.
		/// </summary>
		/// 
		/// <param name="value">The value to validate.</param>
		/// <param name="cultureInfo">The culture to use.</param>
		/// 
		/// <returns><see cref="ValidationResult.ValidResult"/> if <paramref name="value"/>
		///   is valid; otherwise, another <see cref="ValidationResult"/> instance is
		///   returned.</returns>
		/// 
		private ValidationResult ValidateInput( object value, CultureInfo cultureInfo )
		{
			ValidatorException vx;

			if( !_validator.Validate(value != null ? value.ToString() : string.Empty, cultureInfo, out vx) )
				return new ValidationResult(false, vx.Message);

			return ValidationResult.ValidResult;
		}

		/// <summary>
		/// Validates the specified binding group.
		/// </summary>
		/// 
		/// <param name="group">The binding group to validate.</param>
		/// <param name="cultureInfo">The culture to use.</param>
		/// 
		/// <returns><see cref="ValidationResult.ValidResult"/> if <see cref="ItemIndex"/>
		///   is a valid index, <see cref="PropertyName"/> is neither <c>null</c> nor empty and
		///   the received value is valid; otherwise, another <see cref="ValidationResult"/>
		///   instance is returned.</returns>
		/// 
		private ValidationResult ValidateGroup( BindingGroup group, CultureInfo cultureInfo )
		{
			if( group.Items.Count > _itemIndex && !string.IsNullOrWhiteSpace(_propertyName) )
			{
				object value;
				group.TryGetValue(group.Items[_itemIndex], _propertyName, out value);

				return ValidateInput(value, cultureInfo);
			}

			return ValidationResult.ValidResult;
		}

		#endregion
	}
}

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
Germany Germany
I am a software developer since many years and have worked on several large projects especially in financial sectors and the logistics industry.

My favorite programming languages are C, C++ und newly C#.

I am the architect and chief developer of Tricentis TDM Studio (former Q-up) - a generator that primarily creates template based synthetic data for software testing.

Comments and Discussions