Я использую правило проверки для TextBox для проверки строки ввода пользователя. Текст привязывается к свойству с плавающей запятой в модели представления, и механизм привязки WPF достаточно умен, чтобы автоматически преобразовать строку в число с плавающей запятой для меня.
Однако, когда проверка не удалась, привязка, кажется, считывает старое значение. Это приводит к тому, что я получаю красную рамку вокруг текстового поля, хотя текст вернулся к последнему приемлемому значению с плавающей запятой.
Вопрос. Как убедиться, что ошибочный вводимый текст не перезаписывается механизмом привязки автоматически при сбое проверки? Привязка должна быть двусторонней.
Я должен упомянуть, что я делаю небольшой трюк в своем ValidationRule, где я позволяю ему находить текущую модель представления из локатора модели представления и использую подход INotifyDataErrorInfo к модели представления. Я нашел это отличным решением, так как это означает, что ViewModel HasError соберет для меня все ошибки проверки (и это позволит мне применить проверку в правилах проверки или в модели представления при установке свойства). Преимущество разрешения проверки Правило применения проверки с использованием INotifyDataErrorInfo в модели представления заключается в том, что проверка может быть применена до автоматического преобразования строки в число с плавающей запятой, обеспечивая выполнение проверки даже тогда, когда пользователь вводит «Hello World», что приводит к исключению (проглоченному механизм привязки) во время автоматического преобразования в число с плавающей запятой. Это позволяет мне сохранить тип плавающего свойства на виртуальной машине и при этом выполнить проверку.
XAML
<TextBox Grid.Row="2" Grid.Column="2" x:Name="txtPreHeight"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
VerticalAlignment="Center"
Template="{DynamicResource TextBoxBaseControlTemplateMainScreen}">
<TextBox.Text>
<Binding
Path="PreHeight"
ValidatesOnExceptions="False"
NotifyOnValidationError="True"
ValidatesOnNotifyDataErrors="True"
UpdateSourceTrigger="LostFocus"
>
<Binding.ValidationRules>
<validationrules:PreHeightValidationRule ViewModelType="GotoPositionViewModel" Min="0" Max="100" ValidationStep="RawProposedValue"/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
<i:Interaction.Triggers>
<helper:RoutedEventTrigger RoutedEvent="{x:Static Validation.ErrorEvent}">
<cmd:EventToCommand Command="{Binding SetFocusOnValidationErrorCommand}"
PassEventArgsToCommand="True" />
</helper:RoutedEventTrigger>
</i:Interaction.Triggers>
</TextBox>
Правило проверки
class PreHeightValidationRule : ValidationRule
{
private ValidationService validationService_;
private Int32 min_ = Int32.MaxValue;
private Int32 max_ = Int32.MinValue;
private string viewModelType_ = null;
public PreHeightValidationRule()
{
validationService_ = ServiceLocator.Current.GetInstance<Validation.ValidationService>();
}
public Int32 Min
{
get { return min_; }
set { min_ = value; }
}
public Int32 Max
{
get { return max_; }
set { max_ = value; }
}
public string ViewModelType
{
get { return viewModelType_; }
set { viewModelType_ = value; }
}
public override ValidationResult Validate(object value, CultureInfo cultureInfo, BindingExpressionBase owner)
{
ValidationResult result = base.Validate(value, cultureInfo, owner);
ViewModel.ViewModelBaseWithNavigation vm;
System.Reflection.Assembly asm = typeof(ViewModelLocator).Assembly;
Type type = null;
if (type == null)
type = asm.GetType(ViewModelType);
if (type == null)
type = asm.GetType("TeachpendantControl.ViewModel." + ViewModelType);
vm = (ViewModel.ViewModelBaseWithNavigation)ServiceLocator.Current.GetInstance(type);
ICollection<string> validationErrors = new List<string>();
try
{
validationService_.ValidatePreHeight(value.ToString(), ref validationErrors, Min, Max);
}
catch (Exception e)
{
validationErrors.Add("Failed to validate, Exception thrown " + e.Message);
}
finally
{
vm.UpdateValidationForProperty(((BindingExpression)owner).ResolvedSourcePropertyName, validationErrors, validationErrors.Count == 0);
}
return new ValidationResult(validationErrors.Count == 0, validationErrors);
}
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
return new ValidationResult(false, null);
}
}