2

I have two TextBox controls (as follows) and would like to pass the Text of the first TextBox [x:Name="defPointFrom1Txt"] into the ValidationRule [MinIntegerValidationRule] for the second TextBox [x:Name="defPointTo1Txt"] instead of the current value of 1. I could do this in code by naming the validation rule and setting based off an event when the value in the first TextBox changes. However, is there a way to do this in the XAML to keep all the validation logic in one place?

            <TextBox x:Name="defPointFrom1Txt" Grid.Row="2" Grid.Column="1" Style="{StaticResource lsDefTextBox}" 
                     Text="{Binding Path=OffensePointsAllowed[0].From}" IsEnabled="False"/>
            <TextBox x:Name="defPointTo1Txt" Grid.Row="2" Grid.Column="2" Style="{StaticResource lsDefTextBox}"
                     LostFocus="defPointTo1Txt_LostFocus">
                <TextBox.Text>
                    <Binding Path="OffensePointsAllowed[0].To" StringFormat="N1">
                        <Binding.ValidationRules>
                            <gui:MinIntegerValidationRule Min="1"/>
                        </Binding.ValidationRules>
                    </Binding>
                </TextBox.Text>
            </TextBox>

My validation rule code is below for completeness.

  public class IntegerValidationRule : ValidationRule
{

    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        float controlValue;
        try
        {
            controlValue = int.Parse(value.ToString());
        }
        catch (FormatException)
        {
            return new ValidationResult(false, "Value is not a valid integer.");
        }
        catch (OverflowException)
        {
            return new ValidationResult(false, "Value is too large or small.");
        }
        catch (ArgumentNullException)
        {
            return new ValidationResult(false, "Must contain a value.");
        }
        catch (Exception e)
        {
            return new ValidationResult(false, string.Format("{0}", e.Message));
        }
        return ValidationResult.ValidResult;
    }

}

public class MinIntegerValidationRule : IntegerValidationRule
{
    public int Min { get; set; }

    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {

        ValidationResult retValue = base.Validate(value, cultureInfo);
        if (retValue != ValidationResult.ValidResult)
        {
            return retValue;
        }
        else
        {
            float controlValue = int.Parse(value.ToString());
            if (controlValue < Min)
            {
                return new ValidationResult(false, string.Format("Please enter a number greater than or equal to {0}.",Min)); 
            }
            else
            {
                return ValidationResult.ValidResult;
            }
        }
    }
}

UPDATE:

In response to the below answers I am attempting to create a DependencyObject. I did that as follows, but don't know how to use that in the ValidationRule code (or even that I created it properly).

public abstract class MinDependencyObject : DependencyObject
{
    public static readonly DependencyProperty MinProperty =
      DependencyProperty.RegisterAttached(
      "Min", typeof(int), 
      typeof(MinIntegerValidationRule),
      new PropertyMetadata(), 
      new ValidateValueCallback(ValidateInt)
      );

    public int Min
    {
        get { return (int)GetValue(MinProperty); }
        set { SetValue(MinProperty, value); }
    }
    private static bool ValidateInt(object value)
    {
        int test;
        return (int.TryParse(value.ToString(),out test));
    }
}
Harrison
  • 3,843
  • 7
  • 22
  • 49
  • You're on a good way. How is `ValidateValueCallback` implemented? – DHN Mar 19 '13 at 15:17
  • 1
    It was implemented by checking the value.ToString can successfully be parsed to integer. I gave up on doing this in XAML. After looking at the "correct" solution, I decided set the Min and Max ranges in code based on events. Although I would prefer this logic to be in the XAML, the "correct" solution is a workaround since `ValidationRule` doesn't inherit from `DependencyObject`. Therefore you cannot set a `DependencyProperty` directly. Even after creating a `DependencyProperty` separately and putting it in the class you still can't use it for Binding. See link in answer below ... – Harrison Mar 19 '13 at 16:23

3 Answers3

1

You can't set binding on the Min property because it is not a dependencyproperty. What I used to do, was create a validation property attribute on viewmodel which gives me the class instance object and then I perform my validation based on that.

In your case I would create Min as a dependency object.

TYY
  • 2,702
  • 1
  • 13
  • 14
  • I've never created a custom DependencyObject. Can you explain how to do that. I've looked at the documentation and it is quite confusing. I'll post an edit above for what I've done so far. – Harrison Mar 18 '13 at 16:02
  • @Harrison I meant DependencyProperty. – TYY Mar 18 '13 at 16:34
  • Because ValidationRule does not inherit from DependencyObject you can not create a DependencyProperty on that class (or classes that inherit from it). – Harrison Mar 18 '13 at 17:54
  • Yes that is correct but there are ways around it as is discussed in here http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/982e2fcf-780f-4f1c-9730-cedcd4e24320/ – TYY Mar 18 '13 at 18:13
0

Well if you think on Binding you will have to implement a relative huge overhead to use it, because your validation class is already inheriting from another class. Problem is for using Binding the binding target must be a DependencyProperty (as you can read here), which you cannot implement directly in your validation class.

So you could create e.g. an AttachedProperty for your validation classes, so that you're able to use Binding. You can find some information here.

DHN
  • 4,807
  • 3
  • 31
  • 45
0

This post Attaching a Virtual Branch to the Logical Tree in WPF By Josh Smith, 6 May 2007 outlines a solution to this issue.

Harrison
  • 3,843
  • 7
  • 22
  • 49