Привязка свойства модели к сообщению проверки TextBox - PullRequest
0 голосов
/ 26 марта 2019

Я пытаюсь связать свойство моей модели со свойством элемента управления TextBox.Когда свойство имеет строковое значение, TextBox отображает его как сообщение проверки (желательно красная граница и подсказка).И когда свойство имеет нулевую или пустую строку, сообщение проверки не отображается.

Это будет выглядеть примерно так:

<TextBox Text="{Binding FirstName}" ValidationText="{Binding Errors.FirstName}" />

Кажется, что это должно быть так же просто, как связатьсвойство text, но я не могу его получить.

Ответы [ 3 ]

1 голос
/ 04 апреля 2019

Если вы хотите связать сообщение проверки с 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>

Надеюсь, это поможет!

0 голосов
/ 03 апреля 2019

Надеюсь, это поможет вам

<p>FirstName <span style="color:red;">*</span></p>
@Html.TextBoxFor(model => model.FirstName, htmlAttributes: new { maxlength = "100", autocomplete = "off" })
@Html.ValidationMessageFor(model => model.FirstName)
0 голосов
/ 29 марта 2019

Существует несколько способов проверки в WPF.

Я лично предпочитаю многоразовые пользовательские правила проверки, и мне нравится наследовать от Binding вместо того, чтобы постоянно писать все эти мелочи (например, UpdateSourceTrigger) в xaml, или использовать раздутый полный синтаксис тегов для добавления правил проверки.

Вы хотите иметь свойство, к которому можно привязать пользовательский текст ошибки проверки. Одна возможность состоит в том, чтобы использовать прикрепленное свойство, к которому вы можете привязать и которое затем используется правилом проверки для возврата ошибки. Мы можем инкапсулировать все в пользовательский класс привязки:

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 класс более правильно, чтобы отличать его от других привязок , если вы решите следовать моим предпочтениям.

Несколько слов о реализации. Обратите внимание на правило проверки конструктор , необходимо указать, когда мы хотим получить контроль для проверки. В этом случае: когда необработанное значение изменяется в представлении. Другое дело, что нам нужно получить доступ к цели привязки для получения присоединенного свойства, поэтому используется перегрузка с BindingExpression, а другая (требуется при наследовании от ValidationRule) просто возвращает.

красный пансион и наконечник инструмента предпочтительнее

По умолчанию Validation.ErrorTemplate обеспечит красную рамку, и вы можете легко добавить подсказку:

ToolTip="{Binding RelativeSource={RelativeSource self}, Path=(Validation.Errors)[0].ErrorContent}"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...