Как реализовать валидацию INotifyDataErrorInfo для отдельного свойства объекта модели
Есть некий объект бизнес модели Participant который имеет множество текстовых свойств, содержащих полное и краткое имя субъекта, каждое в 6 падежах, итого 12 свойств:
public class Participant
{
//...
public string NameShort1 {get; set;}
public string NameShort2 {get; set;}
public string NameShort3 {get; set;}
public string NameShort4 {get; set;}
public string NameShort5 {get; set;}
public string NameShort6 {get; set;}
public string NameLong1 {get; set;}
public string NameLong2 {get; set;}
public string NameLong3 {get; set;}
public string NameLong4 {get; set;}
public string NameLong5 {get; set;}
public string NameLong6 {get; set;}
//...
}
Очевидно, что в моей модели представления, которая реализована через INotifyPropertyChanged я привязываю экземпляр данного объекта целиком, а не как набор из 12+ свойств привязки, чтобы не захламлять код, примерно так:
private Participant selectedParticipant;
public Participant SelectedParticipant
{
get { return selectedParticipant; }
set
{
selectedParticipant = value;
OnPropertyChanged("SelectedParticipant");
}
}
Соответствующее представление имеет стопку текстбоксов для редактирования текстовых полей:
<StackPanel>
<local:CustomTextbox LabelText="И:" Text="{Binding SelectedParticipant.NameLong1}" />
<local:CustomTextbox LabelText="Р:" Text="{Binding SelectedParticipant.NameLong2}" />
<local:CustomTextbox LabelText="Д:" Text="{Binding SelectedParticipant.NameLong3}" />
<local:CustomTextbox LabelText="В:" Text="{Binding SelectedParticipant.NameLong4}" />
<local:CustomTextbox LabelText="Т:" Text="{Binding SelectedParticipant.NameLong5}" />
<local:CustomTextbox LabelText="П:" Text="{Binding SelectedParticipant.NameLong6}" />
</StackPanel>
Проблема возникает, когда я пытаюсь использовать INotifyDataErrorInfo на свойствах объекта SelectedClient не меняя конфигурацию привязки. Ниже приведена моя попытка реализовать валидацию свойства NameLong1:
private Participant selectedParticipant;
public Participant SelectedParticipant
{
get { return selectedParticipant; }
set
{
//Удаляю ранее созданные ошибки
dataErrorVM.ClearErrors("SelectedParticipant.NameLong1");
//Проверяю NameLong1 на длину строки - не более 10 символов
if (value.NameLong1.Length > 10)
dataErrorVM.AddError("SelectedParticipant.NameLong1", "name is too long");
selectedParticipant = value;
OnPropertyChanged("SelectedParticipant");
}
}
Изменение имени в текстбоксе и смена фокуса с текстбокса не запускает сеттер для SelectedClient. Но даже если запустить сеттер иными способами, то ошибка валидации не воспринимается в представлении (красная рамках вокруг текстбокса). Я подозреваю что дело в том,что имя свойства "SelectedParticipant.NameLong1" записано некорректно, но не знаю правильного способа его записи.
Eсли я создаю отдельное свойство привязки для NameLong1 и каждого другого свойства, то валидация работает нормально, но количество писанины при таком подходе резко возрастает.
UPD Руководствуясь комментарием @Kotomi я во-первых заменил кастомный текстбокс на стандартный текстбокс для ясности, а во-вторых провел сравнительный тест 2х текстбоксов привязанных по-разному:
<!--Текстбокс привязанный через объект
selectedClient.
Предпочтительный мной вариант, но сеттер не
вызывается при изменении значения, а интерфейс
игнорирует ошибку-->
<TextBox
Text="{Binding SelectedParticipant.NameLong1,
ValidatesOnNotifyDataErrors=True,
NotifyOnValidationError=True,
UpdateSourceTrigger=PropertyChanged}"
/>
<!--Текстбокс, привязанный напрямую к отдельному
свойству NameLong1.
Работает как надо: текстбокс краснеет при превышении
лимита символов и возвращается обратно при стирании
строки-->
<TextBox
Text="{Binding NameLong1,
ValidatesOnNotifyDataErrors=True,
NotifyOnValidationError=True,
UpdateSourceTrigger=PropertyChanged}"
/>
Модель представления:
private Participant selectedParticipant;
public Participant SelectedParticipant
{
get { return selectedParticipant; }
set
{
dataErrorVM.ClearErrors("SelectedParticipant.NameLong1");
if (value.NameLong1.Length > 10)
dataErrorVM.AddError("SelectedParticipant.NameLong1", "name is too long!!");
selectedParticipant = value;
if (isEditEnabled == true)
IsEditEnabled = false;
OnPropertyChanged(nameof(SelectedParticipant));
OnPropertyChanged("VisibilityCompany");
OnPropertyChanged("VisibilityPerson");
}
}
public string NameLong1
{
get { return selectedParticipant.NameLong1; }
set
{
dataErrorVM.ClearErrors("NameLong1");
if (value.Length > 10)
{ dataErrorVM.AddError("NameLong1", "name is too long!!"); }
selectedParticipant.NameLong1 = value;
OnPropertyChanged(nameof(NameLong1));
}
}