Skip to content

WPF Form Validation Strategy Without Initial Display Errors, Re-callable ValidForm() and Validation on Submit Button

Hi Guys,

Well after the last few months of building a commercial WPF app (and learning a lot along the way!) I’ve been generally delighted with the experience. A few things I feel could be a lot more polished, or a lot more thought out, but thems the breaks and we can only hope to see some improvements by Visual Studio 2012.

One of the trickiest and sadly, largest shortcoming of WPF I found was a trivial way to perform WPF form validation. It can get very complicated.

So I thought I might just post quickly some strategies I have implemented over the last few days and hopefully you guys can find some value in it and won’t need to go hunting yourselves.

I mainly illustrate a simple Username/Password TextBox Login validation scenario and to understand a bit more on how to set that up with the PasswordBoxAssistant class see the original post on this StackOverflow.com article: http://stackoverflow.com/questions/8942259/error-handling-in-wpf-passwordbox

My approach uses the standard IDataErrorInfo class.

Firstly, I put a call to a new method called OnDataUpdated() in each setter of my view-bound property, for instance:

        private string username;
        public string Username
        {
            get { return username; }
            set
            {
                username = value;
                OnDataUpdated();
            }
        }

        private string password;
        public string Password
        {
            get { return password; }
            set
            {
                password = value;
                OnDataUpdated();
            }
        }

Then inside OnDataUpdated() mark a private field boolean as true indicating data has changed for the first time (FormType was only necessary for my business case):

    private void OnDataUpdated()
    {
       dataChanged = true;
       // .. Any other universal RaisePropertyChanged() events you may want to call to get your UI into sync. Eg. RaisePropertyChanged(() => CanConfirm);
    }

Then in my IDataErrorInfo indexer property I do the following (I split it out so ValidForm() can be called manually to perform form validation too.

    public string this[string columnName]
            {
                get
                {
                    string result = null;
                    if (columnName == "Username")
                    {
                        // If other payment amounts have fully paid for balance, and cash amount has been entered, deny
                        if (!ValidForm(FormType.Step1, columnName))
                            result = "Please enter the username field.";
                    }
                    else if (columnName == "Password")
                    {
                        if (!ValidForm(FormType.Step1, columnName))
                            result = "Please enter the password field.";
                    }
                    return result;
                }
            }
        /// summary>
        /// Test if valid form.
        /// /summary>
        /// param name="formType">Specify which form we should validate./param>
        /// param name="columnName">If ommitted, entire form will be validated./param>
        /// returns>
        private bool ValidForm(FormType formType, string columnName = null)
        {
            // This field is used to denote when data has changed on the form.
            // If data has changed, we know we can activate any form validation.
            // We do not activate the form validation until after a user has typed
            // something in at least.
            if (!dataChanged) return true;
            var errors = false;
            if (formType == FormType.Step1 && ((string.IsNullOrEmpty(columnName) || columnName == "Username") && string.IsNullOrEmpty(Username)))
                errors = true;
            if (formType == FormType.Step1 && ((string.IsNullOrEmpty(columnName) || columnName == "Password") && string.IsNullOrEmpty(Password)))
                errors = true;
            return !errors;
        }

Works beautifully. Validation occuring great and most importantly bridges the gap on a large shortcoming — validation styles ONLY appear once the user commences editing the form.

If you want some extra icing on the cake, you can comment in my RaisePropertyChanged(() => CanConfirm); in the OnDataUpdated() method and bind that to your Confirm Button IsEnabled={Binding CanConfirm} with the associated property:

/// summary>
/// Can the user confirm step 1?
/// /summary>
public bool CanConfirm
{
    get { return ValidForm(FormType.Step1); }
}

and your button will only be enabled when your form is valid too. :)

Enjoy! and best of luck with the behemoth that is WPF.

I don’t have time right now, but I can put a working sample project up on request; just leave me a comment.

VN:F [1.9.10_1130]
Rating: 5.0/5 (2 votes cast)
VN:F [1.9.10_1130]
Rating: 0 (from 0 votes)
WPF Form Validation Strategy Without Initial Display Errors, Re-callable ValidForm() and Validation on Submit Button, 5.0 out of 5 based on 2 ratings
Bookmark and Share
kick it on DotNetKicks.com
Shout it

NOW, FOR A WORD FROM OUR SPONSORS

3 Comments

  1. Pavel

    I want to suggest you to use children of the System.ComponentModel.DataAnnotations.ValidationAttribute.

    So your code will look something like:

    [RequiredAttribute(ErrorMessage ="Please enter the username field.")]
    public string Username{…..}
    private string username;

    public virtual string this[string columnName]
    {
    get
    {
    return dataChanged ? AttributesValidation.Validate(this, columnName):string.Empty; }
    }

    where AttributesValidation is a static class showed here: http://pastebin.com/73yCBnzK

    Now you can simply put any attributes you want without tons of if statements.

    VA:F [1.9.10_1130]
    Rating: 5.0/5 (1 vote cast)
    VA:F [1.9.10_1130]
    Rating: 0 (from 0 votes)
    Posted on 17-Aug-12 at 1:10 pm | Permalink
  2. Eduardo Gonçalves

    Hello Graham !
    Your post is great !

    We are from Brazil. We are about to migrate our applications to WPF, and we have some doubts about that powerfull tool. If you could contribute with your working sample, we’ll be greatful.

    Feel free to contact us anytime…

    Thank you !

    VA:F [1.9.10_1130]
    Rating: 0.0/5 (0 votes cast)
    VA:F [1.9.10_1130]
    Rating: 0 (from 0 votes)
    Posted on 17-Aug-12 at 11:41 pm | Permalink
  3. Graham O'Neale

    Ok I will try and do this tonight for you Eduardo.

    Glad the post was helpful!

    VN:F [1.9.10_1130]
    Rating: 0.0/5 (0 votes cast)
    VN:F [1.9.10_1130]
    Rating: 0 (from 0 votes)
    Posted on 20-Aug-12 at 1:37 pm | Permalink

Post a Comment

Your email is never published nor shared. Required fields are marked *
*
*

My name is Graham O'Neale and I'm a software architect from Gold Coast, Australia. I am an overtime thinker, full time coder and awake part time in the real world. I have a keen interest in software development, particularly in the realm of programming (C#, ASP.NET, ASP.NET MVC, LINQ (2 SQL), Entity Framework, Silverlight, Blend, WCF, WPF) and a keen interest in the cutting edge and innovation. I have a new found love for design patterns, ALT.NET practices and well crafted software architecture. The purpose of this blog is to express any thoughts, findings, tips and gripes along my travels in the wonderful world of coding and technology...