Search code examples
c#wpfdatatemplaterelaycommandvalidationrule

How do I check if all textboxes inside ItemsControl are valid


I have this template for an itemscontrol:

<DataTemplate DataType="{x:Type models:StringParameter}">
         <TextBox materialDesign:HintAssist.Hint="{Binding Name}">
             <TextBox.Text>
                 <Binding Path="Value">
                     <Binding.ValidationRules>
                         <ınteractiveCode:NotEmptyValidationRule ValidatesOnTargetUpdated="True"></ınteractiveCode:NotEmptyValidationRule>
                     </Binding.ValidationRules>
                 </Binding>
             </TextBox.Text>
         </TextBox>
     </DataTemplate>

And I have a button that works with a command, I want it to get enabled when all validations are met in ItemsControl. But I can't find a way to reach textboxes which are inside data templates.


Solution

  • I have a simple approach to solve this specific issue. I have created a ValidationChecker class that will check for existence of validation errors using IsValid method.

    public class ValidationChecker : Freezable
    {
        public static List<DependencyObject> elements = new List<DependencyObject>();
    
        public static int GetValidationObject(DependencyObject obj)
        {
            return (int)obj.GetValue(ValidationObjectProperty);
        }
    
        public static void SetValidationObject(DependencyObject obj, int value)
        {
            obj.SetValue(ValidationObjectProperty, value);
        }
    
        // Using a DependencyProperty as the backing store for ErrorCount.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ValidationObjectProperty =
            DependencyProperty.RegisterAttached("ValidationObject", typeof(DependencyObject), typeof(ValidationChecker), new PropertyMetadata(null, OnValueChanged));
    
    
        public static bool IsValid()
        {
            foreach (var item in elements)
            {
                if (Validation.GetHasError(item)) return false;
            }
            return true;
        }
    
        private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            elements.Add(d);
        }
    
        protected override Freezable CreateInstanceCore()
        {
            return new ValidationChecker();
        }
    }
    

    ValidationObject attached property can be implemented as like below

    <DataTemplate>
        <TextBox local:ValidationChecker.ValidationObject="{Binding RelativeSource={RelativeSource Self}}">
             <TextBox.Text>
                 <Binding Path="Value">
                     <Binding.ValidationRules>
                          <local:NotEmptyValidationRule ValidatesOnTargetUpdated="True"></local:NotEmptyValidationRule>
                     </Binding.ValidationRules>
                  </Binding>
              </TextBox.Text>
           </TextBox>
    </DataTemplate>
    

    You have already mentioned that your Button has been bind to a Command. So implement CanExecute method for the Command and call ValidationChecker.Isvalid(). Don't forget to invoke RaiseCanExecute method for this Command whenever you need.