C# 验证失败时禁用保存按钮
正如你可能从标题中看到的,我将要问一些以前被问过很多次的问题。但是,在阅读了所有其他问题之后,我仍然找不到一个解决问题的好办法 我有一个带有基本验证的模型类:C# 验证失败时禁用保存按钮,c#,wpf,mvvm,C#,Wpf,Mvvm,正如你可能从标题中看到的,我将要问一些以前被问过很多次的问题。但是,在阅读了所有其他问题之后,我仍然找不到一个解决问题的好办法 我有一个带有基本验证的模型类: partial class Player : IDataErrorInfo { public bool CanSave { get; set; } public string this[string columnName] { get { string
partial class Player : IDataErrorInfo
{
public bool CanSave { get; set; }
public string this[string columnName]
{
get
{
string result = null;
if (columnName == "Firstname")
{
if (String.IsNullOrWhiteSpace(Firstname))
{
result = "Geef een voornaam in";
}
}
if (columnName == "Lastname")
{
if (String.IsNullOrWhiteSpace(Lastname))
{
result = "Geef een familienaam in";
}
}
if (columnName == "Email")
{
try
{
MailAddress email = new MailAddress(Email);
}
catch (FormatException)
{
result = "Geef een geldig e-mailadres in";
}
}
if (columnName == "Birthdate")
{
if (Birthdate.Value.Date >= DateTime.Now.Date)
{
result = "Geef een geldige geboortedatum in";
}
}
CanSave = true; // this line is wrong
return result;
}
}
public string Error { get { throw new NotImplementedException();} }
}
partial class Player : IDataErrorInfo
{
private delegate string Validation(string value);
private Dictionary<string, Validation> columnValidations;
public List<string> Errors;
public Player()
{
columnValidations = new Dictionary<string, Validation>();
columnValidations["Firstname"] = delegate (string value) {
return String.IsNullOrWhiteSpace(Firstname) ? "Geef een voornaam in" : null;
}; // Add the others...
errors = new List<string>();
}
public bool CanSave { get { return Errors.Count == 0; } }
public string this[string columnName]
{
get { return this.GetProperty(columnName); }
set
{
var error = columnValidations[columnName](value);
if (String.IsNullOrWhiteSpace(error))
errors.Add(error);
else
this.SetProperty(columnName, value);
}
}
}
每次属性更改时都会执行此验证(因此每次用户在文本框中键入字符时):
这很好用。验证发生(绑定的PropertyChanged
代码在VM中的CurrentPlayer属性上完成,该属性是Player的对象)
我现在想做的是在验证失败时禁用保存按钮
首先,最简单的解决方案似乎可以在这个线程中找到:CanSave
将为真,甚至
尽管还有其他字段仍然无效)ErrorCount
属性。但是当我在每次属性更改时(以及在每个键入的字符时)进行验证时,这也是不可能的-我如何知道何时增加/减少错误计数
解决这个问题的最好办法是什么
谢谢本文将单个验证移动到属性中:
public partial class Player : IDataErrorInfo
{
Dictionary<string, string> _errorInfo;
public Player()
{
_errorInfo = new Dictionary<string, string>();
}
public bool CanSave { get { return _errorInfo.Count == 0; }
public string this[string columnName]
{
get
{
return _errorInfo.ContainsKey(columnName) ? _errorInfo[columnName] : null;
}
}
public string FirstName
{
get { return _firstName;}
set
{
if (String.IsNullOrWhiteSpace(value))
_errorInfo.AddOrUpdate("FirstName", "Geef een voornaam in");
else
{
_errorInfo.Remove("FirstName");
_firstName = value;
}
}
}
}
公共部分类玩家:IDataErrorInfo
{
字典错误信息;
公共玩家()
{
_errorInfo=新字典();
}
公共bool可以保存{get{return{u errorInfo.Count==0;}
公共字符串此[string columnName]
{
得到
{
返回_errorInfo.ContainsKey(columnName)?_errorInfo[columnName]:null;
}
}
公共字符串名
{
获取{return\u firstName;}
设置
{
if(String.IsNullOrWhiteSpace(value))
_errorInfo.AddOrUpdate(“FirstName”,“geefeen voornaam in”);
其他的
{
_errorInfo.Remove(“名字”);
_firstName=值;
}
}
}
}
(您必须处理Dictionary
AddOrUpdate
扩展方法)。这与您的错误计数想法类似。我已经实现了中所示的映射方法,在C中,这称为a,我使用它来进行验证:
partial class Player : IDataErrorInfo
{
public bool CanSave { get; set; }
public string this[string columnName]
{
get
{
string result = null;
if (columnName == "Firstname")
{
if (String.IsNullOrWhiteSpace(Firstname))
{
result = "Geef een voornaam in";
}
}
if (columnName == "Lastname")
{
if (String.IsNullOrWhiteSpace(Lastname))
{
result = "Geef een familienaam in";
}
}
if (columnName == "Email")
{
try
{
MailAddress email = new MailAddress(Email);
}
catch (FormatException)
{
result = "Geef een geldig e-mailadres in";
}
}
if (columnName == "Birthdate")
{
if (Birthdate.Value.Date >= DateTime.Now.Date)
{
result = "Geef een geldige geboortedatum in";
}
}
CanSave = true; // this line is wrong
return result;
}
}
public string Error { get { throw new NotImplementedException();} }
}
partial class Player : IDataErrorInfo
{
private delegate string Validation(string value);
private Dictionary<string, Validation> columnValidations;
public List<string> Errors;
public Player()
{
columnValidations = new Dictionary<string, Validation>();
columnValidations["Firstname"] = delegate (string value) {
return String.IsNullOrWhiteSpace(Firstname) ? "Geef een voornaam in" : null;
}; // Add the others...
errors = new List<string>();
}
public bool CanSave { get { return Errors.Count == 0; } }
public string this[string columnName]
{
get { return this.GetProperty(columnName); }
set
{
var error = columnValidations[columnName](value);
if (String.IsNullOrWhiteSpace(error))
errors.Add(error);
else
this.SetProperty(columnName, value);
}
}
}
部分职业玩家:IDataErrorInfo
{
私有委托字符串验证(字符串值);
私有字典验证;
公开列表错误;
公共玩家()
{
columnValidations=新字典();
columnValidations[“Firstname”]=委托(字符串值){
返回字符串.IsNullOrWhiteSpace(Firstname)?“geefeen voornaam in”:null;
};//添加其他。。。
错误=新列表();
}
公共bool可以保存{get{返回错误。计数==0;}}
公共字符串此[string columnName]
{
get{返回this.GetProperty(columnName);}
设置
{
var error=columnValidations[columnName](值);
if(String.IsNullOrWhiteSpace(错误))
错误。添加(错误);
其他的
this.SetProperty(columnName,value);
}
}
}
此方法适用于数据批注。您还可以将“IsValid”属性绑定到保存按钮以启用/禁用
public abstract class ObservableBase : INotifyPropertyChanged, IDataErrorInfo
{
#region Members
private readonly Dictionary<string, string> errors = new Dictionary<string, string>();
#endregion
#region Events
/// <summary>
/// Property Changed Event
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
#endregion
#region Protected Methods
/// <summary>
/// Get the string name for the property
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="expression"></param>
/// <returns></returns>
protected string GetPropertyName<T>(Expression<Func<T>> expression)
{
var memberExpression = (MemberExpression) expression.Body;
return memberExpression.Member.Name;
}
/// <summary>
/// Notify Property Changed (Shorted method name)
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="expression"></param>
protected virtual void Notify<T>(Expression<Func<T>> expression)
{
string propertyName = this.GetPropertyName(expression);
PropertyChangedEventHandler handler = this.PropertyChanged;
handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
/// <summary>
/// Called when [property changed].
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="expression">The expression.</param>
protected virtual void OnPropertyChanged<T>(Expression<Func<T>> expression)
{
string propertyName = this.GetPropertyName(expression);
PropertyChangedEventHandler handler = this.PropertyChanged;
handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
#region Properties
/// <summary>
/// Gets an error message indicating what is wrong with this object.
/// </summary>
public string Error => null;
/// <summary>
/// Returns true if ... is valid.
/// </summary>
/// <value>
/// <c>true</c> if this instance is valid; otherwise, <c>false</c>.
/// </value>
public bool IsValid => this.errors.Count == 0;
#endregion
#region Indexer
/// <summary>
/// Gets the <see cref="System.String"/> with the specified column name.
/// </summary>
/// <value>
/// The <see cref="System.String"/>.
/// </value>
/// <param name="columnName">Name of the column.</param>
/// <returns></returns>
public string this[string columnName]
{
get
{
var validationResults = new List<ValidationResult>();
string error = null;
if (Validator.TryValidateProperty(GetType().GetProperty(columnName).GetValue(this), new ValidationContext(this) { MemberName = columnName }, validationResults))
{
this.errors.Remove(columnName);
}
else
{
error = validationResults.First().ErrorMessage;
if (this.errors.ContainsKey(columnName))
{
this.errors[columnName] = error;
}
else
{
this.errors.Add(columnName, error);
}
}
this.OnPropertyChanged(() => this.IsValid);
return error;
}
}
#endregion
}
公共抽象类ObservableBase:INotifyPropertyChanged,IDataErrorInfo
{
#区域成员
私有只读字典错误=新建字典();
#端区
#地区活动
///
///属性更改事件
///
公共事件属性更改事件处理程序属性更改;
#端区
#区域保护方法
///
///获取属性的字符串名称
///
///
///
///
受保护的字符串GetPropertyName(表达式)
{
var memberExpression=(memberExpression)expression.Body;
返回memberExpression.Member.Name;
}
///
///Notify属性已更改(短接方法名称)
///
///
///
受保护的虚拟void Notify(表达式)
{
string propertyName=this.GetPropertyName(表达式);
PropertyChangedEventHandler处理程序=this.PropertyChanged;
handler?.Invoke(这是新的PropertyChangedEventArgs(propertyName));
}
///
///在[属性更改]时调用。
///
///
///表情。
受保护的虚拟void OnPropertyChanged(表达式)
{
string propertyName=this.GetPropertyName(表达式);
PropertyChangedEventHandler处理程序=this.PropertyChanged;
handler?.Invoke(这是新的PropertyChangedEventArgs(propertyName));
}
#端区
#区域属性
///
///获取一条错误消息,指示此对象的错误。
///
公共字符串错误=>null;
///
///如果…有效,则返回true。
///
///
///如果此实例有效,则为true;否则为false。
///
public bool IsValid=>this.errors.Count==0;
#端区
#区域索引器
///
///获取具有指定列名的。
///
///
///这个。
///
///列的名称。
///
公共字符串此[string columnName]
{
得到
{
var validationResults=新列表();
字符串错误=null;
如果(Validator.TryValidateProperty(GetType().GetProperty(columnName).GetValue)(this),则新的ValidationContext(this){MemberName=columnName},valida