This project is read-only.

Examples explanation (Updated)

Below a simple explanation of the examples included in the binary distribution.

The Vie Model is a simple class called Interval:


    public class Interval
        public Interval()

        [DynamicRange(typeof(int), "Low of outer interval need to be less than Low of inner interval plus Margin",
            DynamicMaximum = "InnerInterval.Low", DynamicMaximumDelay = "Margin")]
        [Range(0, 100)]
        [FormatError(ErrorMessageResourceType = typeof(MessagesDictionary), ErrorMessageResourceName = "WrongIntervalFormat")]
        [Display(ResourceType=typeof(MessagesDictionary), Name="LowName")]
        public int Low { get; set; }
        [Range(0, 100)]
        [FormatError(ErrorMessageResourceType = typeof(MessagesDictionary), ErrorMessageResourceName = "WrongIntervalFormat")]
        [Display(ResourceType = typeof(MessagesDictionary), Name = "HighName")]
        public int High { get; set; }
        [CustomValidation(typeof(IntervalValidator), "Validate")]
        public Interval InnerInterval { get; set; }
        public int Margin { get; set; }
        public Dictionary OtherInfos { get; set; }


The custom validation attribute just verify that Low is not greater than High. The interval contains another interva inside it (to show how the toolset handles recursive structure).

The DynamicRangeAttribute requires that the Low of the outer interval be less than Low of the inner interval(DynamicMaximum) plus Margin(DynamicMaximumDelay). Possible errors can be eliminated not only modifying the decorated property, but also by modifying the DynamicMaximum. In the User Interface the Margin property is not bound to any control. Therefore, it works just as a constraints between the two Low properties.

The FormatError attribute specifies the error message to display in case of conversion errors, i.e. in case the user input string can not be interpreted as an integer. We used a resource dictionary to specify the error message, but the error message can also be provided directly in the attribute.

Moreover, the class properties can be extended by using a dictionary: OtherInfos. In the examples we added just a single Key called "Persons" that contains a List of Person classes:


public class Person
        public string Name { get; set; }
        public string Surname { get; set; }

The examples show how wrappers are able to cross the boundaries of a dictionary and a List to enable validation on the person classes. The Person classes are displayed as items of a ComboBox.

Simple properties validation is performed immediately while object level validation is performed on the whole hierarchy of the View Model when the user press the send button.

Pressure of the send button has no effect if there are simple property errors. This way the user is forced to correct them before proceeding.  

In the WPF project simple errors are counted by adding an handler for the Validation Error at root of the XAML:


 	private int validationErrorNumbers = 0;
        private void Window_Error(object sender, ValidationErrorEventArgs e)
            if (e.Action == ValidationErrorEventAction.Added) validationErrorNumbers++;
            else validationErrorNumbers--;


One can do the same also in the Silverlight project obviously.

Object level errors in WPF are shown by displaying the Error property that is added to each object as a consequence of the implementation of IDataErrorInfo. This is the only way to show Object level errors in WPF.

Silverlight, instead, has native support for object level errors through the interface INotifyDataErrorInfo, thus such errors are automatically displayed in the validation summaries.

In order to avoid that errors in the inner interval be propagated till the validation summary at top level, an handler for the validation error is attached to the UI representing the InnerInterval:


	private void InnerGrid_BindingValidationError(object sender, ValidationErrorEventArgs e)
            e.Handled = true;


Setting Handled to true blocks the propagation of the RoutedEvent.

The Fake remote Exception button simulates errors arriving asynchronously from a web Service by calling the AddRemoteErrors method:


private ValidationException FakeException(string field, string message)
            return new ValidationException(
                new System.ComponentModel.DataAnnotations.ValidationResult(message, new string[] { field }),
                null, null);

        private void button1_Click(object sender, RoutedEventArgs e)
            wrapper.AddRemoteErrors(new ValidationException[] { FakeException("InnerInterval.Low", "Fake Exception!"), FakeException("OtherInfos[Persons][1].Name", "Fake Exception") });


The target location where to display the errors is defined through a path expression like: "OtherInfos[Persons][1].Name".

In the Silverlight example project we actually call a web service:


        private void button1_Click(object sender, RoutedEventArgs e)

            ErrorServiceClient errorTest = new ErrorServiceClient("BasicHttpBinding_IErrorService");
            errorTest.DoWorkCompleted +=new EventHandler<System.ComponentModel.AsyncCompletedEventArgs>(errorTest_DoWorkCompleted); 
           // wrapper.AddRemoteErrors(new ValidationException[] { FakeException("InnerInterval.Low", "Fake Exception!"), FakeException("OtherInfos[Persons][1].Name", "Fake Exception") });
        private void errorTest_DoWorkCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
            Exception ex = e.Error;
            System.ServiceModel.FaultException<ObservableCollection<ValidationErrorInfo>> ve = ex as System.ServiceModel.FaultException<ObservableCollection<ValidationErrorInfo>>;
            if (ve != null) wrapper.AddValidationFaultExceptionContent(ve.Detail);


The web service is faxe and just return an exception containing all validation errors:


public void DoWork()
            FaultException<IEnumerable<ValidationErrorInfo>> ex = new FaultException<IEnumerable<ValidationErrorInfo>>(
                new ValidationErrorInfo[] { FakeException("InnerInterval.Low", "Fake Exception!"), FakeException("OtherInfos[Persons][1].Name", "Fake Exception") }
        private ValidationErrorInfo FakeException(string field, string message)
                new ValidationErrorInfo
                    Error = message,
                    Members = new string[] { field }

    public interface IErrorService
        void DoWork();

Last edited Dec 15, 2010 at 5:52 PM by frankabbruzzese, version 18


weitzhandler May 11, 2012 at 7:34 AM 
Screenshots would have been helpful here.