简体   繁体   中英

Binding to a ValidationRule in WPF

I am new to WPF. The form's data context includes a StartTime and an EndTime field (using MVVM), which I have successfully bound to their own text boxes. I am trying to create a validation to check that a new user-entered StartTime is before the EndTime value. The following code does not seem to bind the EndTime field to the validation parameter Maximum .

XAML:

<TextBox>
    <TextBox.Text>
        <Binding Path="StartTime" UpdateSourceTrigger="LostFocus" StringFormat="{}{0:hh}:{0:mm}">
            <Binding.ValidationRules>                                            
                <local:ValidateTime>
                    <local:ValidateTime.Maximum>
                        <local:ValidationParameter Parameter="{Binding EndTime, StringFormat=hh\\:mm}" />
                    </local:ValidateTime.Maximum>
                </local:ValidateTime>
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

View model:

public class ValidationParameter : DependencyObject
{
    public static readonly DependencyProperty ParameterProperty = DependencyProperty.Register(
        "Parameter",
        typeof(string),
        typeof(ValidationParameter),
        new FrameworkPropertyMetadata(null));

    public string Parameter
    {
        get { return (string)GetValue(ParameterProperty); }
        set { SetValue(ParameterProperty, value); }
    }
}

public class ValidateTime : ValidationRule
{
    private TimeSpan _Minimum = new TimeSpan(0, 0, 0);
    private TimeSpan _Maximum = new TimeSpan(23, 59, 9);
    private ValidationParameter _MinimumProperty;
    private ValidationParameter _MaximumProperty;

    public ValidationParameter Minimum
    {
        get
        {
            return _MinimumProperty;
        }
        set
        {
            TimeSpan ts;
            if (TimeSpan.TryParse(value.Parameter, out ts))
            {
                _Minimum = ts;
                _MinimumProperty = value;
            }
        }
    }

    public ValidationParameter Maximum
    {
        get 
        {
            return _MaximumProperty;
        }
        set 
        {
            TimeSpan ts;
            if (TimeSpan.TryParse(value.Parameter, out ts))
            {
                _Maximum = ts;
                _MaximumProperty = value;
            }
        }
    }

    public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
    {
        string formattedValue = value.ToString();
        if (Regex.IsMatch(formattedValue, @"^\d{4}$"))
        {
            formattedValue = string.Format("{0}:{1}", formattedValue.Substring(0, 2), formattedValue.Substring(2, 2));
        }
        TimeSpan convertedValue;
        if (TimeSpan.TryParseExact(formattedValue, "g", System.Globalization.CultureInfo.CurrentCulture, out convertedValue))
        {
            if (convertedValue > _Maximum)
            {
                return new ValidationResult(false, string.Format("Time must be before {0}.", _Maximum.ToString("g")));
            }
            else if (convertedValue < _Minimum)
            {
                return new ValidationResult(false, string.Format("Time must be after {0}.", _Minimum.ToString("g")));
            }
            return ValidationResult.ValidResult;
        }
        else
        {
            return new ValidationResult(false, string.Format("'{0}' is not a valid time entry.", value.ToString()));
        }
    }
}

The code works if I set the parameter to a static value like the following, but I need this validation to be dynamic:

<local:ValidateTime.Maximum>
    <local:ValidationParameter Parameter="12:00" />
</local:ValidateTime.Maximum>

First you want to give your TextBox a name like so:

<TextBox Name="StartTime"/>

Then you set the parameter for validation like so:

<local:ValidateTime.Maximum>
    <local:ValidationParameter Parameter="{Binding ElementName=StartTime, Path=Text" />
</local:ValidateTime.Maximum>

If the validation works like you said you should be all set.

You can do the same thing with your EndTime TextBox if you want as well assuming you write a working rule for it

您可能需要解决 ValidationRules不在视觉或逻辑树中的事实,这会导致与DataContextElementNameRelativeSource绑定失败。

In my case

<local:RangeValidation ValidationStep="UpdatedValue"/>

helped. So you pass the DependencyObject as value(.dataitem) including your Datacontext and have no need to pass a parameter to the Validation. BR, Daniel

BTW credits not on mee, just found it but can't remember who gave the hint :)

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