ValidationSummary won't display ValidationResultItems of type ObjectError... why?

Answered ValidationSummary won't display ValidationResultItems of type ObjectError... why?

  • Wednesday, October 05, 2011 2:10 PM
     
     

    Hi,

    I don't know if I'm doing something wrong but here's the thing...

    I have a simple form made of a grid containing textboxes and a validation summary in the end. On the "submit" button I do the following:

     

    private void Button_Click(object sender, RoutedEventArgs e)
            {
                var ccInfo = (CreditCardDepositInfo)((Button)sender).DataContext;
                ccInfo.ValidationErrors.Add(new System.ComponentModel.DataAnnotations.ValidationResult("general error"));
                ccInfo.ValidationErrors.Add(new System.ComponentModel.DataAnnotations.ValidationResult("specific property error",new List<string>(){"CardNumber"}));
                
            }

    I'm using MVVM and this Click event is just for demonstration.

    The ValidationSummary looks like this:

    <sdk:ValidationSummary x:Name="myValSum"  MaxHeight="100">
    </sdk:ValidationSummary>

    (nothing complicated)

    The problem is, it only displays the PropertyErrors and no matter what I try, it will not display errors that are not associated with members of the bound object (the CreditCardDepositInfo object).

    I played around with the ValidationSummary.Filters property and it's not the issue. When looking into the ValidationSummary.Errors property, I see that it's simply not populated like it should be. Only ValidationSummaryItems with type=PropertyErrors are being generated. It's like it is completely ignoring ObjectErrors.

    Another thing I noticed is that each ValidationSummaryItem in the ValidationSummary.Errors collection has a property called context and it is set to null. Isn't this property supposed to be the actual object where the error is coming from? why is it null?

    A side note... I can add Errors to the ValidationSummary manually from the UI but since I'm using MVVM, it is not what I'm looking for.

    So what am I doing wrong here? Is it an actual bug?

    PS I'm using SL5 but I'm sure it is the same in SL4

All Replies

  • Thursday, October 06, 2011 3:31 AM
     
     Answered

    this is taken from MSDN... I guess I missed it when first reading it.

    http://msdn.microsoft.com/en-us/library/system.windows.controls.validationsummary(v=vs.95).aspx

     

    Object level errors are not automatically added to the Errors collection. A ValidationSummaryItem that represents an object level error must be added to the collection by your application code.

     

    So I guess I have to either extend the ValidationSummary control or throw a message to handle this Object Error issue... oh well!

  • Thursday, October 06, 2011 4:44 AM
     
     

    and if you were wondering what I ended up doing...

    here it is:

    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Linq;
    using System.ServiceModel.DomainServices.Client;
    using System.Windows.Controls;
    
    namespace CRM.Client.Common.Extenders
    {
        public class ExtendedValidationSummary : ValidationSummary
        {
            private Entity _context;
    
            public override void OnApplyTemplate()
            {
                base.OnApplyTemplate();
    
                if (this.DataContext == null) return;
                if (!this.DataContext.GetType().IsSubclassOf(typeof(Entity))) return;
                _context = (Entity)this.DataContext;
                _context.PropertyChanged += new PropertyChangedEventHandler(context_PropertyChanged);
    
            }
    
            void context_PropertyChanged(object sender, PropertyChangedEventArgs e)
            {
                if (e.PropertyName != "ValidationErrors") return;
    
                //clear previous object errors
                List<ValidationSummaryItem> errorsToRemove = this.Errors.Where(er => er.ItemType == ValidationSummaryItemType.ObjectError).ToList();
                foreach (var error in errorsToRemove)
                    this.Errors.Remove(error);
    
                //add new errors
                foreach (var error in _context.ValidationErrors)
                {
                    if (error.MemberNames.Count() > 0 || this.Errors.Where(er => er.Message == error.ErrorMessage).Count() > 0) continue;//not and object error... properties are associated
                    this.Errors.Add(new ValidationSummaryItem
                    {
                        Context = _context,
                        ItemType = ValidationSummaryItemType.ObjectError,
                        Message = error.ErrorMessage
                    });
                }
    
            }
    
        }
    }
    

     

    It's just a rough draft. I'm sure you can make it cleaner... but it definitely works!

    Eyal

  • Friday, March 30, 2012 3:36 PM
     
     

    Nice solution for this...

    Glad I stumbled upon it :-)

  • Wednesday, August 01, 2012 8:10 AM
     
     

    @eyal453

    Alternatively, you could do something as follows

    <TextBlock Binding="{Binding Entity, NotifyOnValidationError=True}" Visibility="Collapsed" />

    This will catch object level errors, if you're object implements INotifyDataErrorInfo

    However, this will not catch unbound properties with validation errors.

    For example:

    [Required]

    public string Name{get;set;}

    If the Name property is not bound to any control then no validation errors will be displayed for it.

    In that case you would have to use code similar to what you've written above to display validation errors for the Name property. The tricky part being determining if Name was currently unbound.

     

     

  • Monday, October 29, 2012 12:50 PM
     
     

    Hey eyal453,

    probably as nice approach, but how did you apply this snippet in your code?

  • Monday, November 12, 2012 6:39 AM
     
     

    JazzyJ,

    I guess you meant to bind the 'Text' property of the TextBlock?

    It didn't work for me though. Do you have any more details?

    Thanks,

    cp