Я новичок в WPF MVVM и хотел задать дополнительный вопрос к этой статье: Включить кнопку «Отключить сохранение» во время проверки с помощью IDataErrorInfo Я пытаюсь включить/отключить кнопку сохранения/обновления, если какой-либо из многих элементов управления при проверке формы не прошел/прошел. У меня есть метод IsValid, который проверяет логику проверки модели и возвращает значение True/False, которое будет передано в DelegateCommand в качестве предиката. Вопрос в следующем: моя кнопка имеет следующее свойство IsEnabled{binding IsValid}, это должно проверять все поля, чтобы убедиться, что они соответствуют критериям в модели, возвращает true/false в модель представления, а затем включает кнопку, если все верно. Проблема в том, что после создания экземпляра модели представления объект DelegateCommand создается с проверкой (IsValid) в ложном состоянии и остается таким на протяжении всего жизненного цикла объекта, даже если пользователь заполняет данные в текстовых полях. Как включить кнопку после выполнения всех условий? другими словами, как постоянно проверять и обновлять IsValid, чтобы включать кнопку после подтверждения каждого текстового поля значением true??
Спасибо,
У меня есть следующий код: Модель
public class UserModel : ObservePropertyChanged,IDataErrorInfo
{
private string name;
public string Name
{
get { return name; }
set { name = value; OnPropertyChanged("Name"); }
}
// if there is an error throw an exception
public string Error
{
get { throw new NotImplementedException(); }
}
public string this[string columnName]
{
get
{
string result = null;
if (columnName == "Name")
{
if (string.IsNullOrEmpty(Name))
result = "Please enter a Name";
}
return result;
}
}
// the Josh Way
static readonly string[] ValidatedProperties =
{
"Name"
};
public bool IsValid
{
get
{
foreach (string property in ValidatedProperties)
{
if (GetValidationError(property) != null) // there is an error
return false;
}
return true;
}
}
// a method that checks validation error
private string GetValidationError(string propertyName)
{
string error = null;
switch (propertyName)
{
case "Name":
error = this.ValidateName();
break;
default:
error = null;
throw new Exception("Unexpected property being validated on Service");
}
return error;
}
private string ValidateName()
{
string ErrorMsg = null;
if (string.IsNullOrWhiteSpace(Name))
{
ErrorMsg = "Name can't be empty!";
};
return ErrorMsg;
}
}
** Модель просмотра **
public class UserViewModel:ObservePropertyChanged
{
UserModel model;
public UserViewModel()
{
presentCommand = new DelegateCommand(param => PresentDataMethod(), param => CanSave);
model = new UserModel();
}
private string name;
public string Name
{
get { return name; }
set { name = value; OnPropertyChanged("Name"); }
}
private string info;
public string Info
{
get { return info; }
set { info = value; OnPropertyChanged("Info"); }
}
private DelegateCommand presentCommand;
public DelegateCommand PresentCommand
{
get
{
if (presentCommand==null)
{
presentCommand = new DelegateCommand(param => PresentDataMethod(), param => CanSave);
}
return presentCommand;
}
}
private void PresentDataMethod()
{
Info = $"Your Name is: {Name}.";
}
// The ViewModel then contains a CanSave Property that reads the IsValid property on the Model:
protected bool CanSave
{
get
{
return model.IsValid;
}
}
}
** Вид**
<TextBox x:Name = "Name" HorizontalAlignment = "Left" Height = "34" Margin = "285,145,0,0" TextWrapping = "Wrap"
VerticalAlignment = "Top" Width = "248">
<Binding Path = "Name"
ValidatesOnDataErrors = "True"
UpdateSourceTrigger = "PropertyChanged"
Mode = "TwoWay">
</Binding>
</TextBox>
<Button Content = "Present" FontSize = "20" HorizontalAlignment = "Left"
Margin = "285,184,0,0" VerticalAlignment = "Top" Width = "248" Height = "35"
Command = "{Binding Path=PresentCommand}"
IsEnabled = "{Binding IsValid}"
>
</Button>
Если все, что вы хотите сделать, это обновить кнопку с помощью значения IsValid
, все, что вам нужно сделать, это прослушать любые изменения ДРУГИХ свойств в вашей ViewModel, и когда это произойдет, скажите ему также обновить привязку IsValid
(что на самом деле ваша CanSave
собственность). Вот один из способов сделать это:
** Модель просмотра **
// ...
public UserViewModel()
{
// ...
this.PropertyChanged += OnViewModelPropertyChanged;
}
public void OnViewModelPropertyChanged(object sender, PropertyEventArgs e)
{
// On any property that implements "OnPropertyChanged(propname)", refresh the CanSave binding too!
OnPropertyChanged(nameof(this.CanSave));
}
// ...
Кстати, в целом хорошей практикой кодирования является избегание волшебных слов, таких как OnPropertyChanged("Name")
или OnPropertyChanged("Info")
, потому что вы никогда не знаете, когда разработчику придется переименовывать свои свойства, и если это произойдет, вы не получите здесь ошибку компиляции, и это может быть трудно отлаживать. Лучше всего использовать nameof
, например OnPropertyChanged(nameof(Name))
, чтобы вы знали, что получите ошибку компиляции, если когда-нибудь решите изменить свойство, скажем, на FirstName
вместо Name
.
Разве
UserViewModel
не нужно свойствоIsValid
, чтобы удовлетворить ваше выражение привязки дляIsEnabled
?