UI Validation Problem
-
I am implementing INotifyDataErrorInfo. Here's my base ViewModel
public class \_ViewModelBase : BindableBase, INotifyDataErrorInfo { #region Events public event EventHandler ErrorsChanged; #endregion #region Private Fields public readonly Dictionary\> \_validationErrors = new Dictionary\>(); #endregion #region Properties public bool HasErrors => \_validationErrors.Any(); #endregion #region Public Methods public IEnumerable GetErrors(string propertyName) { return \_validationErrors.ContainsKey(propertyName) ? \_validationErrors\[propertyName\] : null; } #endregion #region Protected Methods protected void AddError(string propertyName, string error) { if (!\_validationErrors.ContainsKey(propertyName)) { \_validationErrors\[propertyName\] = new List(); } if (!\_validationErrors\[propertyName\].Contains(error)) { \_validationErrors\[propertyName\].Add(error); RaiseErrorsChanged(propertyName); } } protected void ClearErrors(string propertyName) { if (\_validationErrors.ContainsKey(propertyName)) { \_validationErrors.Remove(propertyName); { RaiseErrorsChanged(propertyName); } } } #endregion #region Private Methods private void RaiseErrorsChanged(string propertyName) { ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName)); } #endregion }
Here's my CustomerView
-
I am implementing INotifyDataErrorInfo. Here's my base ViewModel
public class \_ViewModelBase : BindableBase, INotifyDataErrorInfo { #region Events public event EventHandler ErrorsChanged; #endregion #region Private Fields public readonly Dictionary\> \_validationErrors = new Dictionary\>(); #endregion #region Properties public bool HasErrors => \_validationErrors.Any(); #endregion #region Public Methods public IEnumerable GetErrors(string propertyName) { return \_validationErrors.ContainsKey(propertyName) ? \_validationErrors\[propertyName\] : null; } #endregion #region Protected Methods protected void AddError(string propertyName, string error) { if (!\_validationErrors.ContainsKey(propertyName)) { \_validationErrors\[propertyName\] = new List(); } if (!\_validationErrors\[propertyName\].Contains(error)) { \_validationErrors\[propertyName\].Add(error); RaiseErrorsChanged(propertyName); } } protected void ClearErrors(string propertyName) { if (\_validationErrors.ContainsKey(propertyName)) { \_validationErrors.Remove(propertyName); { RaiseErrorsChanged(propertyName); } } } #endregion #region Private Methods private void RaiseErrorsChanged(string propertyName) { ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName)); } #endregion }
Here's my CustomerView
That makes no sense - both
nameof(Customer.CustomerName)
andnameof(CustomerName)
will compile to the constant string"CustomerName"
. Are you sure that the view-model property is spelled correctly?
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
-
That makes no sense - both
nameof(Customer.CustomerName)
andnameof(CustomerName)
will compile to the constant string"CustomerName"
. Are you sure that the view-model property is spelled correctly?
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
OK, so I'm not really sure what the problem is here:
private void Validate()
{
ClearErrors("CustomerName");if (string.IsNullOrWhiteSpace(Customer.CustomerName)) { AddError("CustomerName", "The Customer Name cannot be empty."); }
}
The TextBox is bound to Customer.CustomerName. When I remove the text, the error is added, but I don't see anything. I'm guessing I'm not doing this right.
In theory, theory and practice are the same. But in practice, they never are.” If it's not broken, fix it until it is. Everything makes sense in someone's mind.
-
I am implementing INotifyDataErrorInfo. Here's my base ViewModel
public class \_ViewModelBase : BindableBase, INotifyDataErrorInfo { #region Events public event EventHandler ErrorsChanged; #endregion #region Private Fields public readonly Dictionary\> \_validationErrors = new Dictionary\>(); #endregion #region Properties public bool HasErrors => \_validationErrors.Any(); #endregion #region Public Methods public IEnumerable GetErrors(string propertyName) { return \_validationErrors.ContainsKey(propertyName) ? \_validationErrors\[propertyName\] : null; } #endregion #region Protected Methods protected void AddError(string propertyName, string error) { if (!\_validationErrors.ContainsKey(propertyName)) { \_validationErrors\[propertyName\] = new List(); } if (!\_validationErrors\[propertyName\].Contains(error)) { \_validationErrors\[propertyName\].Add(error); RaiseErrorsChanged(propertyName); } } protected void ClearErrors(string propertyName) { if (\_validationErrors.ContainsKey(propertyName)) { \_validationErrors.Remove(propertyName); { RaiseErrorsChanged(propertyName); } } } #endregion #region Private Methods private void RaiseErrorsChanged(string propertyName) { ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName)); } #endregion }
Here's my CustomerView
Being "in error" is the state of the object in question; not a flag or entry in a list. That's transaction oriented versus "online". My "HasErrors" runs all the "validations" on the object and returns true or false anytime it is called (e.g. before saving). No "error lists" to clear etc. You can also retrieve all errors (to show only the first, for example, to avoid overloading thee user). At the same time, all the textboxes in error are "red lined" as expected.
"Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I
-
Being "in error" is the state of the object in question; not a flag or entry in a list. That's transaction oriented versus "online". My "HasErrors" runs all the "validations" on the object and returns true or false anytime it is called (e.g. before saving). No "error lists" to clear etc. You can also retrieve all errors (to show only the first, for example, to avoid overloading thee user). At the same time, all the textboxes in error are "red lined" as expected.
"Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I
See my latest reply to Richard
In theory, theory and practice are the same. But in practice, they never are.” If it's not broken, fix it until it is. Everything makes sense in someone's mind.
-
See my latest reply to Richard
In theory, theory and practice are the same. But in practice, they never are.” If it's not broken, fix it until it is. Everything makes sense in someone's mind.
I think you have a "ValidatesOn..." mismatch. [https://stackoverflow.com/questions/17254847/what-is-the-difference-between-validatesonnotifydataerrors-and-validatesondataer\](https://stackoverflow.com/questions/17254847/what-is-the-difference-between-validatesonnotifydataerrors-and-validatesondataer)
"Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I
-
OK, so I'm not really sure what the problem is here:
private void Validate()
{
ClearErrors("CustomerName");if (string.IsNullOrWhiteSpace(Customer.CustomerName)) { AddError("CustomerName", "The Customer Name cannot be empty."); }
}
The TextBox is bound to Customer.CustomerName. When I remove the text, the error is added, but I don't see anything. I'm guessing I'm not doing this right.
In theory, theory and practice are the same. But in practice, they never are.” If it's not broken, fix it until it is. Everything makes sense in someone's mind.
The errors don't match the property you're binding to. Try using:
const string propertyName = $"{nameof(Customer)}.{nameof(Customer.CustomerName)}";
ClearErrors(propertyName);
f (string.IsNullOrWhiteSpace(Customer.CustomerName))
{
AddError(propertyName, "The Customer Name cannot be empty.");
}
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
-
I think you have a "ValidatesOn..." mismatch. [https://stackoverflow.com/questions/17254847/what-is-the-difference-between-validatesonnotifydataerrors-and-validatesondataer\](https://stackoverflow.com/questions/17254847/what-is-the-difference-between-validatesonnotifydataerrors-and-validatesondataer)
"Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I
OK, I don't get what's wrong here. Here's the CustomerName in my CustomerView
Here's the VM
private void Customer_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
IsChanged = true;ValidateCustomerName();
}
private void ValidateCustomerName()
{
ClearErrors(nameof(Customer.CustomerName));if (string.IsNullOrWhiteSpace(Customer.CustomerName)) { AddError(nameof(Customer.CustomerName), "The Customer Name cannot be empty."); }
}
When I clear out the CustomerName field, the ValidateCustomerName method fires, and the error is added to the errors collection. I just don't see the error text on the UI. However, if instead of binding to Customer.CustomerName, if I put a string property on the VM called CustomerName and use that, then I see the error text.
In theory, theory and practice are the same. But in practice, they never are.” If it's not broken, fix it until it is. Everything makes sense in someone's mind.