Я искал по всему Google и все еще пытаюсь найти правильный ответ. Проблема заключается в следующем, когда я очищаю это текстовое поле, связанное значение не срабатывает.
Итак, проблема в том, что ограниченное значение этого текстового поля не изменяется, если оно становится пустым, но мое правило проверки обнаруживает это и отправляет предупреждение.
Ниже вы можете найти мой фрагмент XAML, правило проверки принадлежности и упомянутое свойство.
XAML-фрагмент
<TextBox Style = "{StaticResource TextBoxErrorStyle}"
Margin = "8 0 0 0"
Visibility = "{Binding AdditionalSurfaceTreatmentInfoVisibility,
Converter = {StaticResource BoolToVisConverter}}"
FontSize = "12" MaxLength = "4" Width = "40"
Height = "25">
<TextBox.Text>
<Binding Path = "AdditionalSurfaceTreatmentInfo"
UpdateSourceTrigger = "PropertyChanged"
NotifyOnSourceUpdated = "True" Mode = "TwoWay"
NotifyOnValidationError = "True">
<Binding.ValidationRules>
<classes:StandardValidationRule ValidatesOnTargetUpdated = "True"/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
Стандартное правило проверки:
public class StandardValidationRule : ValidationRule
{
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
var valueToValidate = value as string;
if (string.IsNullOrEmpty(valueToValidate))
{
return new ValidationResult(false, "Field is mandatory.");
}
return new ValidationResult(true, null);
}
}
Недвижимость:
private string _additionalSurfaceTreatmentInfo;
public string AdditionalSurfaceTreatmentInfo
{
get => _additionalSurfaceTreatmentInfo;
set
{
_additionalSurfaceTreatmentInfo = value;
OnPropertyChanged();
SetOrModifySurfaceTreatment();
Console.WriteLine(string.IsNullOrEmpty(_additionalSurfaceTreatmentInfo).ToString());
}
}
Заранее благодарим вас за ваши усилия. Любая помощь высоко ценится!
Приведенный выше код работает так, как я предпочитаю. Я уже перепробовал все, что касается различных свойств, которые я могу заполнить в ValidationRule. Единственное, что нужно изменить, это то, что когда текстовое поле пусто, оно должно запускать метод OnPropertyChanged(). Таким образом, я могу позже проверить свойство, когда я, например, отправлю команду сохранения.
@JWP Прежде всего, спасибо за ваш ответ! У меня нет большого опыта работы со свойствами зависимостей. У вас есть пример или ресурс, который я могу использовать, чтобы попробовать? Я уже пытался установить точку останова на OnPropertyChange, но программе еще нужно достичь этой точки. Я заметил, что если я удаляю ValidatesOnTargetUpdated = "True", событие OnPropertyChange действительно работает.





Используйте свойство ValidationStep. Пример:
<local:StandardValidationRule ValidationStep = "UpdatedValue"
ValidatesOnTargetUpdated = "True"/>
Но для проверки исходного свойства нужна более сложная логика, так как валидатор получает не значение свойства, а выражение привязки от целевого свойства.
public class StandardValidationRule : ValidationRule
{
private bool gettingValue = false;
private bool isValueReceived = false;
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
if (gettingValue)
{
isValueReceived = true;
return ValidationResult.ValidResult;
}
string? valueToValidate = value as string;
ValidationResult? result = null;
if (valueToValidate is null && value is not null)
{
if (value is BindingExpressionBase bindingExpression)
{
gettingValue = true;
isValueReceived = false;
DependencyObject target = bindingExpression.Target;
var gettingValueExpression = BindingOperations.SetBinding(target, SourceValueProperty, bindingExpression.ParentBindingBase);
if (!isValueReceived)
{
gettingValueExpression.UpdateTarget();
}
valueToValidate = target.GetValue(SourceValueProperty)?.ToString();
target.ClearValue(SourceValueProperty);
gettingValue = false;
}
else
{
result = unvalid;
}
}
if (result is null)
{
result = string.IsNullOrEmpty(valueToValidate)
? unvalid
: ValidationResult.ValidResult;
}
return result;
}
private static readonly ValidationResult unvalid = new ValidationResult(false, "Field is mandatory.");
// Using a DependencyProperty as the backing store for SourceValue. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SourceValueProperty =
DependencyProperty.RegisterAttached("SourceValue", typeof(object), typeof(StandardValidationRule), new PropertyMetadata(null));
}
Есть еще один способ получить исходное значение.
Он основан на использовании метода internal через отражение.
Что многие считают «плохим» способом.
Но работает гораздо эффективнее.
И я думаю вряд ли кто-то будет вносить изменения в метод internal, который уже во многих местах используется.
public static class BindingExpressionHelper
{
private static readonly Func<BindingExpressionBase, DependencyObject, DependencyProperty, object> GetValueOfBindingExpression;
static BindingExpressionHelper()
{
Type beType = typeof(BindingExpressionBase);
var beMethod = beType
.GetMethod("GetValue", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, new Type[] { typeof(DependencyObject), typeof(DependencyProperty) })
?? throw new Exception("GetValue method not found.");
var beFunc = (Func<BindingExpressionBase, DependencyObject, DependencyProperty, object>)
beMethod.CreateDelegate(typeof(Func<BindingExpressionBase, DependencyObject, DependencyProperty, object>));
GetValueOfBindingExpression = beFunc;
}
/// <summary>Returns the source value of this binding expression.</summary>
/// <param name = "bindingExpression">The binding expression whose value to get.</param>
/// <returns>The value of the binding expression received.</returns>
public static object? GetSourceValue(this BindingExpressionBase bindingExpression)
{
DependencyObject target = bindingExpression.Target;
DependencyProperty targetProperty = bindingExpression.TargetProperty;
var value = GetValueOfBindingExpression(bindingExpression, target, targetProperty);
return value;
}
}
public class StandardValidationRule : ValidationRule
{
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
string? valueToValidate = value as string;
ValidationResult? result = null;
if (valueToValidate is null && value is not null)
{
if (value is BindingExpressionBase bindingExpression)
{
valueToValidate = bindingExpression.GetSourceValue()?.ToString();
}
else
{
result = unvalid;
}
}
if (result is null)
{
result = string.IsNullOrEmpty(valueToValidate)
? unvalid
: ValidationResult.ValidResult;
}
return result;
}
private static readonly ValidationResult unvalid = new ValidationResult(false, "Field is mandatory.");
}
Спасибо за ответ! Если я добавлю эту строку, OnPropertyChanged снова будет работать, но стиль ошибки проверки всегда будет оставаться активным, независимо от того, является ли значение нулевым, пробельным, пустым или заполненным.
@KamphuisCoding, прости! Я забыл о том, что при проверке источника приходит не значение свойства. Я дополнил свой ответ реализацией проверки источника.
Привет @EldHasp, нет проблем, приятель. Решения, которые вы указали, работают как шарм! Еще раз большое спасибо за ваше время и усилия! Из любопытства, какое из двух решений вы бы реализовали сами?
Второй вариант — с отражением. Но я бы хорошо это задокументировал, чтобы в случае возникновения проблем (кто знает, какие еще изменения они могут внести в .Net), пользователи понимали причину проблемы и знали, как ее решить.
Я бы использовал DependencyProperty для AdditionalSurfaceTreatementInfo, у меня они всегда работали. Но позвольте мне спросить, дает ли что-нибудь установка точки останова в OnPropertyChanged? Я предполагаю, что нет.