Правила валидации применяются, когда целевое значение (TextBox.Text
в этом случае) присваивается источнику (в этом случае свойство viewmodel). BindingGroup.CancelEdit()
очищает состояние ошибки и копирует исходные значения в целевые свойства.
При установке UpdateSourceTrigger="PropertyChanged"
на этом TextBox.Text
Binding
, на каждом нажатии клавиши в текстовом поле валидацию Binding
работает на TextBox.Text
, и если она проходит проверку, она копирует целевое значение для свойства источника. Это означает, что он копирует TextBox.Text
в yourViewModel.nome
.
Например, yourViewModel.nome
изначально null.
Пользователь нажимает кнопку в текстовом поле и набирает «Арнольд». yourViewModel.nome
обновляется шесть раз, пока пользователь печатает, один раз для каждого символа.
Пользователь нажимает кнопку Cancel
, что вызывает вызов BindingGroup.CancelEdit()
.
BindingGroup.CancelEdit()
, ведет себя как задумано, копирует значение тока из yourViewModel.nome
, строка "Arnold"
, чтобы TextBox.Text
.
Это проблема, которую вы видите.
С BindingGroup
, проверка is фиксация. Если поле проверено и проходит проверку, оно выполняется. И как только вы совершите, слишком поздно отменять.
Если вы хотите повременить проверки и проверки/фиксации группы полей вместе, то вы используете BindingGroup
и UpdateSourceTrigger="Explicit"
, что приводит к валидации/фиксация произойдет только на BindingGroup.CommitEdit()
, или когда вы звоните UpdateSource() on the
сам Binding`:
myTextBox.GetBindingExpression(TextBox.TextProperty).UpdateSource();
Лекция заканчивается, ответ начинается
Если вы хотите проверить без фиксации, вы будете иметь, чтобы сделать что-то немного другое.
Самого простое и самый простое, что нужно сделать, это установить UpdateSourceTrigger="Explicit"
на креплениях и обрабатывать TextChanged
на текстовых полях:
XAML
<TextBox CharacterCasing="Upper" TextChanged="anyValidatedTextBox_TextChanged">
<TextBox.Text>
<Binding Path="nome" UpdateSourceTrigger="Explicit" Mode="TwoWay">
<Binding.ValidationRules>
<ValidationRules:IsNotNull/>
<ValidationRules:MyStringLengthValidationRule Length="45"/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
Codebehind
private void anyValidatedTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
(sender as TextBox)
.GetBindingExpression(TextBox.TextProperty)
.ValidateWithoutUpdate();
}
или вы может сделать весь BindingGroup
утвердить без изменений:
private void anyValidatedTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
myFormStackPanel.BindingGroup.ValidateWithoutUpdate();
}
Другой Ответ
Более обобщенный способ сделать это, более ортодоксальный MVVM, чтобы написать поведение, которое делает то же самое.
using System;
using System.ComponentModel;
using System.Windows;
namespace HollowEarth.Behaviors
{
public static class Validation
{
#region Validation.OnPropertyChanged Attached Property
public static DependencyProperty GetOnPropertyChanged(FrameworkElement obj)
{
return (DependencyProperty)obj.GetValue(OnPropertyChangedProperty);
}
public static void SetOnPropertyChanged(FrameworkElement obj, DependencyProperty value)
{
obj.SetValue(OnPropertyChangedProperty, value);
}
public static readonly DependencyProperty OnPropertyChangedProperty =
DependencyProperty.RegisterAttached("OnPropertyChanged", typeof(DependencyProperty), typeof(Validation),
new PropertyMetadata(null, OnPropertyChanged_PropertyChanged));
private static void OnPropertyChanged_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var obj = d as FrameworkElement;
if (e.OldValue != null)
{
DependencyPropertyDescriptor.
FromProperty(e.OldValue as DependencyProperty, obj.GetType())
.RemoveValueChanged(obj, ValidateHandler);
}
if (e.NewValue != null)
{
DependencyPropertyDescriptor.
FromProperty(e.NewValue as DependencyProperty, obj.GetType())
.AddValueChanged(obj, ValidateHandler);
}
}
static void ValidateHandler(object sender, EventArgs args)
{
var fe = (FrameworkElement)sender;
var dprop = GetOnPropertyChanged(fe);
fe.GetBindingExpression(dprop).ValidateWithoutUpdate();
}
#endregion Validation.OnPropertyChanged Attached Property
}
}
XAML:
<TextBox
xmlns:hb="clr-namespace:HollowEarth.Behaviors"
CharacterCasing="Upper"
hb:Validation.OnPropertyChanged="{x:Static TextBox.TextProperty}"
>
<TextBox.Text>
<Binding Path="nome" UpdateSourceTrigger="Explicit" Mode="TwoWay">
<Binding.ValidationRules>
<ValidationRules:IsNotNull/>
<ValidationRules:MyStringLengthValidationRule Length="45"/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
Я предпочел бы, что поведение применительно к BindingGroup
или владелец BindingGroup
«s, а не к отдельным полям, но когда я попробовал это, BindingGroup.BindingExpressions
и BindingGroup.Items
были пусты на момент его применения. BindingGroup
не имеет событий, и в его коллекции нет событий. Бьюсь об заклад, вы можете что-то сделать с поведением владельца BindingGroup
, где вы делаете крючки на LayoutUpdated
, но мое внимание начинает блуждать. Я оставлю это как упражнение для ученика.
В качестве дополнительного упражнения вы можете просто скопировать и вставить мой код, даже не прочитав его. Вот что я делаю, девять раз из десяти.
Пожалуйста, вставьте текст кода в свой вопрос. Никто не хочет прищуриться от размытого скриншота. –
Извините, была ошибкой. – StanleyIPC
Намного лучше, спасибо. Это немного грубо на моем iPhone с дополнительным отступом, но я посмотрю, когда доберусь до офиса. –