将模型属性绑定到TextBox验证消息

时间:2019-03-26 16:09:57

标签: c# wpf validation

我正在尝试将模型的属性绑定到openssl控件上的属性。当属性具有字符串值时,TextBox会将其呈现为验证消息(首选红色边界和工具提示)。而且,如果该属性具有null或空字符串,则不会呈现任何验证消息。

它看起来像这样:

TextBox

似乎应该像绑定text属性一样容易,但是我似乎无法理解。

3 个答案:

答案 0 :(得分:1)

如果您想将 Validation Message 绑定到模型的Property,我建议您实现INotifyDataErrorInfo,然后可以随时进行验证,得到错误并显示所需的特定消息,例如,如下所示:

//Model class
[Required]
[CustomValidation(typeof(CustomValidation), "ValidateBirthday")]
public string Birthday
{
    get => _birthday;
    set => Set(ref _birthday, value);
}

//Custom Validation Class
public static ValidationResult ValidateBirthday(object inObj, ValidationContext inContext)
{
     Model model = (Model) inContext.ObjectInstance;

     string text = model.Birthday;

     DateTime birthday = text.ToDate();

     if (birthday == default)
     {
         return new ValidationResult("Birthday is not valid", new List<string> {"Birthday"});
     }

     // Future
     if (birthday >= DateTime.Now.Date)
     {
         return new ValidationResult("Birthday is in the future", new List<string> {"Birthday"});
     }

     // Past
     return birthday <= DateTime.Now.Date.AddYears(-200)
         ? new ValidationResult("Birthday too old", new List<string> {"Birthday"})
         : ValidationResult.Success;
 }

您只需要验证模型并让消息显示在所需的文本框中:

public void ValidateModel()
{
    ValidationContext context = new ValidationContext(this);
    List<ValidationResult> results = new List<ValidationResult>();

    Validator.TryValidateObject(this, context, results, true);

    foreach (KeyValuePair<string, List<string>> valuePair in _validationErrors.ToList())
    {
        if (!results.All(r => r.MemberNames.All(m => m != valuePair.Key)))
        {
            continue;
        }

        _validationErrors.TryRemove(valuePair.Key, out List<string> _);
        RaiseErrorChanged(valuePair.Key);
    }

    IEnumerable<IGrouping<string, ValidationResult>> q = from r in results
        from m in r.MemberNames
        group r by m
        into g
        select g;

    foreach (IGrouping<string, ValidationResult> prop in q)
    {
        List<string> messages = prop.Select(r => r.ErrorMessage).ToList();

        if (_validationErrors.ContainsKey(prop.Key))
        {
            _validationErrors.TryRemove(prop.Key, out List<string> _);
        }

        _validationErrors.TryAdd(prop.Key, messages);
        RaiseErrorChanged(prop.Key);
    }
}

您可以使用Validation.ErrorTemplate来绑定并显示消息:

<TextBox Text="{Binding Birthday, UpdateSourceTrigger=PropertyChanged}">
    <Validation.ErrorTemplate>
        <ControlTemplate>
            <StackPanel>
                <!-- Placeholder for the TextBox itself -->
                <AdornedElementPlaceholder x:Name="textBox"/>
                <TextBlock Text="{Binding [0].ErrorContent}" Foreground="Red"/>
            </StackPanel>
        </ControlTemplate>
    </Validation.ErrorTemplate>
</TextBox>

希望有帮助!

答案 1 :(得分:0)

有多种方法可以在WPF中进行验证。

我个人更喜欢可重用的自定义验证规则,并且我喜欢从Binding继承,而不必在xaml中重复编写所有这些小东西(例如UpdateSourceTrigger)或使用or肿的全标签语法来添加验证规则。

您想要一个可以绑定自定义验证错误文本的属性。一种可能性是使用可以绑定到的附加属性,然后验证规则将其用于返回错误。我们可以将所有内容封装到自定义绑定类中:

public class Bind : Binding
{
    // validation rule
    class Rule : ValidationRule
    {
        public Rule() : base(ValidationStep.RawProposedValue, true) { }

        public override ValidationResult Validate(object value, CultureInfo cultureInfo) => ValidationResult.ValidResult;
        public override ValidationResult Validate(object value, CultureInfo cultureInfo, BindingExpressionBase owner)
        {
            if (!string.IsNullOrEmpty((string)value))
                return new ValidationResult(false, GetError(owner.Target));
            return base.Validate(value, cultureInfo, owner);
        }
    }

    // attached property to hold error text
    public static string GetError(DependencyObject obj) => (string)obj.GetValue(ErrorProperty);
    public static void SetError(DependencyObject obj, string value) => obj.SetValue(ErrorProperty, value);
    public static readonly DependencyProperty ErrorProperty = DependencyProperty.RegisterAttached("Error", typeof(string), typeof(Bind));

    // custom binding
    public Bind() : base() => Init();
    public Bind(string path) : base(path) => Init();
    void Init()
    {
        UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
        ValidationRules.Add(new Rule());
    }
}

在xaml中的用法:

<TextBox Text="{local:Bind FirstName}" local:Bind.Error="{Binding FirstNameError}" />

如果您决定遵循我的偏好,则必须更恰当地命名Bind类,以区别于其他绑定

关于实施的几句话。请注意验证规则constructor,它需要指定何时要让控件进行验证。在这种情况下:当原始值在视图中更改时。另一件事是我们需要访问绑定目标以检索附加属性,这就是为什么使用BindingExpression的重载而另一个(从ValidationRule继承时需要)重载的原因。

  

首选红色寄宿生和工具提示

默认Validation.ErrorTemplate将提供红色边框,您可以轻松添加工具提示:

ToolTip="{Binding RelativeSource={RelativeSource self}, Path=(Validation.Errors)[0].ErrorContent}"

答案 2 :(得分:-2)

希望这对您有帮助

<p>FirstName <span style="color:red;">*</span></p>
@Html.TextBoxFor(model => model.FirstName, htmlAttributes: new { maxlength = "100", autocomplete = "off" })
@Html.ValidationMessageFor(model => model.FirstName)