简体   繁体   中英

WPF: Binding to validation rule's DependencyProperty

I want to validate text box value against standard rules, and couple of them is Min and Max value. The problem is, that I need to have this values configurable (for example in settings file).

I have validation rule:

public class TextBoxWithIntegerValidation : ValidationRule
    {
        private Int32RangeChecker _validRange;

        public Int32RangeChecker ValidRange
        {
            get { return _validRange; }
            set { _validRange = value; }
        }

        public override ValidationResult Validate(object value, CultureInfo cultureInfo)
        {
            var str = value as string;
            if (str == null)
            {
                return new ValidationResult(false, Resources.TextResources.TextBoxIsEmpty_ErrorMessage);
            }

            int intValue = -1;
            if (!int.TryParse(str, out intValue))
            {
                return new ValidationResult(false, Resources.TextResources.TextBoxNotIntegerValue_ErrorMessage);
            }

            if (intValue < ValidRange.Minimum)
            {
                return new ValidationResult(false, 
                    string.Format(Resources.TextResources.TextBoxValueLowerThanMin_ErrorMessage, ValidRange.Minimum));
            }

            return new ValidationResult(true, null);
        }
    }

Int range checker:

 public class Int32RangeChecker : DependencyObject
{
    public int Minimum
    {
        get { return (int)GetValue(MinimumProperty); }
        set { SetValue(MinimumProperty, value); }
    }

    public static readonly DependencyProperty MinimumProperty =
        DependencyProperty.Register("Minimum", typeof(int), typeof(Int32RangeChecker), new UIPropertyMetadata(0));

    public int Maximum
    {
        get { return (int)GetValue(MaximumProperty); }
        set { SetValue(MaximumProperty, value); }
    }

    public static readonly DependencyProperty MaximumProperty =
        DependencyProperty.Register("Maximum", typeof(int), typeof(Int32RangeChecker), new UIPropertyMetadata(100));

}

And the text box validation:

<TextBox>
<TextBox.Text>
    <Binding Path="Interval" UpdateSourceTrigger="PropertyChanged" ValidatesOnNotifyDataErrors="True">
        <Binding.ValidationRules>
            <validationRules:TextBoxWithIntegerValidation>
                <validationRules:TextBoxWithIntegerValidation.ValidRange>
                    <validationRules:Int32RangeChecker
                            Minimum="{Binding IntervalMinValue}"
                        />
                </validationRules:TextBoxWithIntegerValidation.ValidRange>
            </validationRules:TextBoxWithIntegerValidation>
        </Binding.ValidationRules>
    </Binding>
</TextBox.Text>

TextBox placed inside the UserControl and appropriate ViemModel placed in the control DataContext.

The problem is: property IntervalMinValue is not bound to the validation rule. If I set it manually - works fine, but not with the binding.

The problem is the Int32RangeChecker object is attached to an object that is not part of the visual tree and therefore does not have access to the view model. If you look at your output window you will see this error...

System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=IntervalMinValue; DataItem=null; target element is 'Int32RangeChecker' (HashCode=32972388); target property is 'Minimum' (type 'Int32')

To fix this you need to connect the binding of the Minimum property to an element of the visual tree. One way to do this is to add an invisible dummy element and bind to the data context on it...

    <FrameworkElement x:Name="dummyElement" Visibility="Hidden"/>
    <TextBox>
        <TextBox.Text>
            <Binding Path="Interval" UpdateSourceTrigger="PropertyChanged" ValidatesOnNotifyDataErrors="True">
                <Binding.ValidationRules>
                    <local:TextBoxWithIntegerValidation>
                        <local:TextBoxWithIntegerValidation.ValidRange>
                            <local:Int32RangeChecker
                        Minimum="{Binding Source={x:Reference dummyElement}, Path=DataContext.IntervalMinValue}"
                    />
                        </local:TextBoxWithIntegerValidation.ValidRange>
                    </local:TextBoxWithIntegerValidation>
                </Binding.ValidationRules>
            </Binding>
        </TextBox.Text>
    </TextBox>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM