Как я могу заставить WPF НЕ отображать ошибки проверки при первоначальном отображении элемента управления?
Когда я сначала показываю свой экран пользователю, я бы предпочел, чтобы все сообщения проверки не отображались для обязательных полей и, прежде чем пользователь имел возможность заполнить любое из полей формы. Я установил UpdateSourceTrigger
в моих привязках к LostFocus
, но ошибки все еще отображаются при первом отображении элемента управления. Есть ли способ обойти это?
XAML:
<TextBox Text="{Binding Path=OpeningOdometer, ValidatesOnDataErrors=True, UpdateSourceTrigger=LostFocus}" />
ViewModel:
[Required(ErrorMessage = "Please enter the opening odometer.")]
[Range(0, Double.MaxValue, ErrorMessage = "Opening Odometer must be a positive number")]
public string OpeningOdometer
{
get { return _openingOdometer; }
set
{
_openingOdometer = value;
NotifyOfPropertyChange(() => OpeningOdometer);
}
}
// Implementation of IDataErrorInfo
public string this[string columnName]
{
get
{
// This uses the System.ComponentModel.DataAnnotations placed on
// the OpeningOdometer property to produce an error string
// if the value of the property is in violation of any of the
// annotated rules.
return _valHelper.GetErrorsForProperty(columnName, this);
}
}
Ответы
Ответ 1
Я не ставил логику проверки в индексе. Это превращает контроль над временем проверки на представление. В вашей схеме представление запускает проверку, когда запрашивает информацию об ошибке свойства. Я не знаю всех обстоятельств, в которых это произойдет, и я готов поспорить, что вы тоже.
Вместо этого я поместил логику проверки свойств (точнее, вызов функции проверки) в свой сеттер. Я сохраняю сообщение об ошибке в словаре, указанном на имени свойства, и попрошу индексатора найти сообщение об ошибке для свойства.
По умолчанию сообщение об ошибке обновляется с текущим значением свойства. Всякий раз, когда представление обновляет свойство и запрашивает его новую информацию об ошибке, он получит правильный ответ.
Но у вас также есть довольно мелкомасштабный контроль над тем, что на самом деле в этом словаре. Если вы хотите, чтобы свойство отображалось в пользовательском интерфейсе как действительное, просто очистите его сообщение об ошибке в словаре (и поднимите PropertyChanged
, чтобы пользовательский интерфейс знал, чтобы получить новое сообщение об ошибке). Или вы можете установить поля поддержки свойств вместо самих свойств, минуя проверку, когда вы создаете объект модели представления.
Ответ 2
Вы можете получить более качественные ответы, если попытаетесь опубликовать фрагмент вашего соответствующего кода /XAML. Это облегчило бы воспроизведение и устранение значительной части догадок.
Попробуйте установить ValidatesOnTargetUpdated="False"
в правилах проверки и посмотрите, помогает ли это.
Ответ 3
Просто чтобы указать, как я справился с этим использованием IDataErrorInfo
...
Я поместил вызов нового метода под названием OnDataUpdated()
в каждый набор моего свойства, связанного с представлением, например:
private string username;
public string Username
{
get { return username; }
set
{
username = value;
OnDataUpdated();
}
}
private string password;
public string Password
{
get { return password; }
set
{
password = value;
OnDataUpdated();
}
}
Затем внутри OnDataUpdated()
отметьте приватное поле boolean как true
, указывающее, что данные были изменены в первый раз (FormType
было необходимо только для моего бизнес-кейса):
private void OnDataUpdated()
{
dataChanged = true;
// .. Any other universal RaisePropertyChanged() events you may want to call to get your UI into sync. Eg. RaisePropertyChanged(() => CanConfirm);
}
Затем в свойстве indexer IDataErrorInfo
я делаю следующее (я разделил его так, чтобы "ValidForm()" можно вызвать вручную, чтобы выполнить проверку формы тоже.
public string this[string columnName]
{
get
{
string result = null;
if (columnName == "Username")
{
// If other payment amounts have fully paid for balance, and cash amount has been entered, deny
if (!ValidForm(FormType.Step1, columnName))
result = "Please enter the username field.";
}
else if (columnName == "Password")
{
if (!ValidForm(FormType.Step1, columnName))
result = "Please enter the password field.";
}
return result;
}
}
/// <summary>
/// Test if valid form.
/// </summary>
/// <param name="formType">Specify which form we should validate.</param>
/// <param name="columnName">If ommitted, entire form will be validated.</param>
/// <returns></returns>
private bool ValidForm(FormType formType, string columnName = null)
{
// This field is used to denote when data has changed on the form.
// If data has changed, we know we can activate any form validation.
// We do not activate the form validation until after a user has typed
// something in at least.
if (!dataChanged) return true;
var errors = false;
if (formType == FormType.Step1 && ((string.IsNullOrEmpty(columnName) || columnName == "Username") && string.IsNullOrEmpty(Username)))
errors = true;
if (formType == FormType.Step1 && ((string.IsNullOrEmpty(columnName) || columnName == "Password") && string.IsNullOrEmpty(Password)))
errors = true;
return !errors;
}
Прекрасно работает. Теперь у меня только стили проверки, появляющиеся после того, как пользователь редактирует форму.
Если вы хотите получить дополнительную глазурь на торте, вы можете прокомментировать мой RaisePropertyChanged(() => CanConfirm);
в методе OnDataUpdated()
и связать это с вашей кнопкой подтверждения IsEnabled={Binding CanConfirm}
с соответствующим свойством:
/// <summary>
/// Can the user confirm step 1?
/// </summary>
public bool CanConfirm
{
get { return ValidForm(FormType.Step1); }
}
и ваша кнопка будет включена, только если ваша форма также действительна.:)
Наслаждайтесь! и удачи с бегемотом, который является WPF.