Archive for March, 2010

CodeStock 2010 Sessions

Hello everyone!

I have a few sessions submitted to CodeStock 2010 this year!  These sessions are on the multi-touch and Silverlight 4 Validation topics I have been looking into recently.  If you enjoyed the blogs and want more detail and guidance on the topics please vote for my sessions!

You can find them at

http://www.codestock.org/Sessions/intro-to-touch-and-multitouch-in-wpf-and-silverlight.aspx

http://www.codestock.org/Sessions/model-validation-in-silverlight-4.aspx

Thanks again and have a good day!

No Comments

Silverlight 4 INotifyDataErrorInfo

Hello everyone!

So recently I have been looking into Silverlight 4’s new INotifyDataErrorInfo interface for a solution to validation.  I have to say that I really like how this works.

I have built a sample validation framework that models can use to build a simple and easy-to-use system for adding validation that is supported by Silverlight.

You can download the sample code here, but let’s look at a few things.

First let’s take a look at the basics of the Interface.  INotifyDataErrorInfo has three primary items:

  • event ErrorsChanged
  • IEnumerable GetErrors(string propertyName)
  • bool HasErrors

The ErrorsChanged event is the key to validation notification in this system.  When ErrorsChanged is fired, a binding that specifies ValidatesOnNotifyDataErrors=True will then call the GetErrors() method with the property name of the property for which the validation rule exists, or null if you want to specify the object as a whole.  So when you create your custom validation engine and you want to notify Silverlight that the validation state for a property (or object) has changed, you will raise this event.

One cool thing to note about the fact ErrorsChanged is an event, is that it can now support async validation rules.  Imagine in your validation system you make an async call back to the server; when it returns, you can raise this event!

private void HandleRuleResult(string propertyName, RuleKey<T> ruleKey, RuleArgs args)
        {
            if (args.IsValid)
            {
                var foundRule = (from re in ErrorMessages
                                 where re.PropertyName == propertyName
                                 && re.RuleIdentifier == ruleKey.RuleIdentifier
                                 select re).FirstOrDefault();

                if (foundRule != null)
                {
                    ErrorMessages.Remove(foundRule);
                    OnErrorsChanged(propertyName);
                }
            }
            else
            {
                var foundRule = (from re in ErrorMessages
                                 where re.PropertyName == propertyName
                                 && re.RuleIdentifier == ruleKey.RuleIdentifier
                                 select re).FirstOrDefault();

                if (foundRule == null)
                {
                    RuleError error = new RuleError() { RuleIdentifier = ruleKey.RuleIdentifier, ErrorMessage = args.Message, PropertyName = propertyName };
                    ErrorMessages.Add(error);
                    OnErrorsChanged(propertyName);
                }
            }
        }

        protected void OnErrorsChanged(string propertyName)
        {
            if (ErrorsChanged != null)
                ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));
        }

 

The method of GetErrors() is what the system uses in order retrieve the validation errors when it is notified that the validation rules have changed.  The propertyName parameter will be passed either a single property name, for which you will retrieve your rules, or null, which is your key to retrieve all rules for the entire object.  This is helpful for controls like my custom ValidationSummary control.

It is important to note here that this method needs to be able to get the validation messages after the ErrorsChanged event fires. This means in your custom system, you must have stored your broken validation rules in a way where this can be coded to retrieve before you fire the event.

public System.Collections.IEnumerable GetErrors(string propertyName)
        {
            List<string> errors = null;

            if (propertyName == null)
            {
                if (ErrorMessages.Count > 0)
                {
                    errors = new List<string>();

                    foreach (var re in ErrorMessages)
                    {
                        errors.Add(re.ErrorMessage);
                    }
                }
            }
            else
            {
                var foundRules = (from re in ErrorMessages
                                  where re.PropertyName == propertyName
                                  select re).ToList();

                if (foundRules != null && foundRules.Count > 0)
                {
                    errors = new List<string>();
                    foreach (var re in foundRules)
                        errors.Add(re.ErrorMessage);
                }
            }

            return errors;
        }

 

The last piece is the HasErrors property: this is how to notify your objects that the resulting object has errors.  Every time a rule changes you may want to raise OnPropertyChanged for this property and implement its getter in a way where it knows how to count your broken rules.

public bool HasErrors
        {
            get { return ErrorMessages.Count > 0; }
        }

 

So far what we should now realize is that the interface provides us a way to tie our own validation engine directly into Silverlight.  It does not provide a validation engine in itself, but gives you everything you need to notify Silverlight that states have changed.

The sample code posted above provides a sample implementation of how a validation rules engine might be created around this interface.  I was very inspired by CSLA’s (http://www.lhotka.net/) validation rule entry interface so I modeled it somewhat after its pattern.  We have the ability to add rules to our objects via static methods and property names.  These rules are only added once per type and stored statically.  The engine also allows for the creation of async rules and also provides a bindable collection that is populated with broken rules when they are added.

Once again if you would like to download the sample framework and code you can get it here.

I hope you enjoy it and have a good day!

8 Comments