views:

1391

answers:

1

I have a user control which contains a textbox. I have a class called Person which implements IDataErrorInfo interface:

class Person : IDataErrorInfo
{
private bool hasErrors = false;
#region IDataErrorInfo Members

        public string Error
        {            
            get 
            {
                string error = null;
                if (hasErrors)
                {
                    error = "xxThe form contains one or more validation errors";
                }
                return error;
            }
        }

        public string this[string columnName]
        {
            get 
            {
                return DoValidation(columnName);
            }
        }
        #endregion
}

Now the usercontrol exposes a method called SetSource through which the code sets the binding:

public partial class TxtUserControl : UserControl 
    {          
        private Binding _binding;

        public void SetSource(string path,Object source)
        {
            _binding = new Binding(path);
            _binding.Source = source;
            ValidationRule rule;
            rule = new DataErrorValidationRule();
            rule.ValidatesOnTargetUpdated = true;            
            _binding.ValidationRules.Add(rule);
            _binding.ValidatesOnDataErrors = true;
            _binding.UpdateSourceTrigger = UpdateSourceTrigger.LostFocus;
            _binding.NotifyOnValidationError = true;            
            _binding.ValidatesOnExceptions = true;
            txtNumeric.SetBinding(TextBox.TextProperty, _binding);                
        }
...
}

The WPF window that includes the user control has the following code:

public SampleWindow()
    {
        person= new Person();
        person.Age = new Age();
        person.Age.Value = 28;

        numericAdmins.SetSource("Age.Value", person);
    }
    private void btnOk_Click(object sender, RoutedEventArgs e)
    {         

        if(!String.IsNullOrEmpty(person.Error))
        {
            MessageBox.Show("Error: "+person.Error);
        }
    }

Given this code, the binding is working fine, but the validation never gets triggered. Whats wrong with this code?

+1  A: 

Your Age class will need to implement IDataErrorInfo. Your Person class won't be asked to validate the Age's properties.

If that is not an option, I wrote a validation system for WPF that is extensible enough to support this. The URL is here:

In the ZIP is a word document describing it.

Edit: here's one way age could implement IDataErrorInfo without being too smart:

class Constraint 
{
    public string Message { get; set; }
    public Func<bool> Validate;
    public string Name { get; set; }
}

class Age : IDataErrorInfo
{
    private readonly List<Constraint> _constraints = new List<Constraint>();

    public string this[string columnName]
    {
        get 
        {
            var constraint = _constrains.Where(c => c.Name == columnName).FirstOrDefault();
            if (constraint != null)
            {
                if (!constraint.Validate())
                {
                    return constraint.Message;
                }
            }
            return string.Empty;
        }
    }
}

class Person
{
    private Age _age;

    public Person() 
    {
        _age = new Age(
            new Constraint("Value", "Value must be greater than 28", () => Age > 28);
    }
}

Also see this link:

http://www.codeproject.com/KB/cs/DelegateBusinessObjects.aspx

Paul Stovell
Paul,I had a look at the framework that you have developed. Is there any other way of doing this? If you could provide some pointers here it will be great
Ngm
Have Age implement IDataErrorInfo or use a WPF ValidationRule (UI-level validation) - these are the only workarounds I can think of.
Paul Stovell
With my validation framework, you'd just associate the UI control with a rule name (e.g., "AgeValue"), and in your IDataErrorInfo you'd handle validation on the "AgeValue" rule. In my framework there's no coupling between property names and validation rule names the way there is in WPF's validation.
Paul Stovell
Thanks, I was able to achieve the desired results with the use of a custom validation rule derived from ValidationRule class
Ngm