a validation block problem in wpf

Topics: Validation Application Block
Nov 9, 2010 at 2:16 AM

I am using validation block in my wpf application, and I use app.config to store validation rules,
and binding mechanism to do the validation.

here are some code snippet.

<!-- app.config -->
  <validation>
    <type name="LWBioAnalyzer.Model.BioChemistryInfo" defaultRuleset="LWRuleset" assemblyName="LWBioAnalyzer">
      <ruleset name="LWRuleset">
        <properties>
          <property name="ChemName">
            <validator type="Microsoft.Practices.EnterpriseLibrary.Validation.Validators.OrCompositeValidator, Microsoft.Practices.EnterpriseLibrary.Validation" messageTemplate="[{0}]{2} must be less than 6." messageTemplateResourceName="" messageTemplateResourceType="" tag="ChemName Length" name="Or Composite Validator">
              <validator type="Microsoft.Practices.EnterpriseLibrary.Validation.Validators.NotNullValidator, Microsoft.Practices.EnterpriseLibrary.Validation" negated="true" messageTemplate="[{0}]Value can be NULL or a length limited string." messageTemplateResourceName="" messageTemplateResourceType="" tag="" name="Not Null Validator"/>
              <validator type="Microsoft.Practices.EnterpriseLibrary.Validation.Validators.StringLengthValidator, Microsoft.Practices.EnterpriseLibrary.Validation" upperBound="5" lowerBound="0" lowerBoundType="Inclusive" upperBoundType="Inclusive" negated="false" messageTemplate="[{0}]{1} must be between {3} and {5} characters." messageTemplateResourceName="" messageTemplateResourceType="" tag="" name="String Length Validator"/> 
            </validator>
          </property>
	  ...
        </properties>
      </ruleset>
    </type>
  </validation>
/// ChemistryModel.cs

  namespace LWBioAnalyzer.Model
  {
    [HasSelfValidation]
    public class BioChemistryInfo : BaseModel, IDataErrorInfo
    {
        static ValidatorFactory valFactory;

        public BioChemistryInfo()
        {
            Reset();

            valFactory = EnterpriseLibraryContainer.Current.GetInstance<ValidatorFactory>();
        }

        public void Reset()
        {
		this.ChemName = "";
	}

	private string _chemName;
        public string ChemName
        {
            get { return this._chemName; }
            set 
            {
                if (this._chemName == value)
                    return;

                this._chemName = value;
                OnPropertyChanged("ChemName");
            }
        }

        #region IDataErrorInfo Members

        public string Error
        {
            get
            {
                if(null != valFactory)
                {
                    StringBuilder error = new StringBuilder();
                    Validator<BioChemistryInfo> chemValidator = valFactory.CreateValidator<BioChemistryInfo>("LWRuleset");
                    ValidationResults results = chemValidator.Validate(this);
                    
                    foreach (var result in results)
                    {
                        error.AppendLine(result.Message);
                    }

                    return error.ToString();
                }

                return string.Empty;
            }

        }

        public string this[string columnName]
        {
            get
            {
                if (null != valFactory)
                {
                    StringBuilder error = new StringBuilder();
                    Validator<BioChemistryInfo> chemValidator = valFactory.CreateValidator<BioChemistryInfo>("LWRuleset");
                    ValidationResults results = chemValidator.Validate(this);

                    foreach (var result in results)
                    {
                        if (result.Key == columnName)
                            return result.Message;
                    }

                    return error.ToString();
                }

                return string.Empty;
            }
        }

        [SelfValidation]
        public void Validate(ValidationResults results)
        {
            string msg = string.Empty;

            if (null != valFactory)
            {
                Validator<BioChemistryInfo> chemValidator = valFactory.CreateValidator<BioChemistryInfo>("LWRuleset");
                ValidationResults cfgChkResults = chemValidator.Validate(this);

                results.AddAllResults(cfgChkResults);
            }

           // other checker
        }

    #endregion
  }
<!-- winChemistryDefine.xaml -->
  <!-- ... -->
  <TextBox Canvas.Left="120" Canvas.Top="70" Width="160" Style="{StaticResource TextBoxStyle}">
            <TextBox.Text>
                <Binding Path="CurrentChemistry.ChemName" >
                    <Binding.ValidationRules>
                        <vab:ValidatorRule
                            SourceType="{x:Type model:BioChemistryInfo}"
                            SourcePropertyName="ChemName">
                        </vab:ValidatorRule>
                    </Binding.ValidationRules>
                </Binding>
            </TextBox.Text>
   </TextBox>
   <!-- ... -->
My problem is when I done an invalid input, the validate() function still returns none error, because the invalid value can not be used to 
update the binding source, so how can I get the true validate results?
Maybe the invalid value should also be updated to the source? Or the validate results should be provide by the validation block?
Hope for you help, and forgive my poor english. ^_^
Nov 9, 2010 at 2:47 AM
Edited Nov 9, 2010 at 2:51 AM

I'm afraid I didn't understand exactly your question but does this statement from the document partly explains your scenario? (Link to the documentation)

"If the value of the validated control that carries the Required validation attribute is empty to begin with, and remains empty during validation, the source is not updated and validation does not occur.
In this particular case the ValidateOnTargetUpdate property will not work either because the null default value of the target will not change. Instead, you can invoke UpdateSource on the binding to
force validation to occur, as shown here.

this.Required.GetBindingExpression(TextBox.TextProperty).UpdateSource();

If it is, then I suppose the validate() function doesn't really get triggerred and the solution is to use the code above?

 

Sarah Urmeneta
Global Technologies and Solutions
Avanade, Inc.
entlib.support@avanade.com

Nov 16, 2010 at 12:13 AM

En, my meaning was how can I know there exists a validation error when I submit a form ? Should I access every control on the window to get that ?

I hope I can use the binding source data to do the validation, but I can't, because the binding source will not be updated when a validation error happens.

thanks very much for your answer.

Nov 17, 2010 at 1:36 AM

Did you verify that the Self Validation (Validate) method gets triggered?  The way I see it is it's not getting fired at all since self validation methods aren't really being called when using xml validation rules in WPF.  The way around would be yes, to access every value of the control, create an instance of a BioChemistryInfo out of those and pass it on the call to Validation.Validate.

 

Sarah Urmeneta
Global Technologies and Solutions
Avanade, Inc.
entlib.support@avanade.com