我有一个名为'CustomerDataContract'的类,它有三个属性:MobilePhone,OfficePhone和PrivatePhone。为了与客户取得联系,必须至少设置一个属性。
我创建了一个Validator-Class并添加了一个名为'CheckForAnyPhoneNumber'的自定义规则来检查是否至少提供了一个电话号码。这几乎解决了我的问题。我唯一的问题是,如果我清除了例如MobilePhone-Attribute,它将被评估并处于错误状态。如果我现在输入OfficePhone号码,则不会重新评估MobilePhone-Attribute并保持错误模式。
知道如何正确解决这个问题吗?我也试过创建一个RuleSet但没有成功。
这是(部分)CustomerDataContract:
public partial class CustomerDataContract
{
public CustomerDataContract Clone()
{
return (CustomerDataContract) MemberwiseClone();
}
public override ValidationResult SelfValidate()
{
return ValidationHelper.Validate<CustomerDataContractValidator, CustomerDataContract>(this);
}
}
所有DataContracts的基类:
[Serializable]
public abstract class BDataModel : IDataErrorInfo, INotifyPropertyChanged
{
[field: NonSerialized]
private ValidationResult _currentState = new ValidationResult();
public ValidationResult CurrentValidationState
{
get { return _currentState; }
set
{
_currentState = value;
OnPropertyChanged("CurrentValidationState");
OnPropertyChanged("IsValid");
OnPropertyChanged("Error");
}
}
#region INotifyPropertyChanged
[field: NonSerialized]
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(params string[] propertyName)
{
propertyName.ToList().ForEach(x =>
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(x));
});
}
#endregion
public virtual ValidationResult SelfValidate()
{
return new ValidationResult();
}
public bool IsValid
{
get
{
if (CurrentValidationState == null)
CurrentValidationState = SelfValidate();
return CurrentValidationState.IsValid;
}
}
#region IDataErrorInfo
public string Error
{
get { return ValidationHelper.GetError(CurrentValidationState); }
}
public string this[string columnName]
{
get
{
CurrentValidationState = SelfValidate();
if (_currentState == null) return string.Empty;
var columnResults = _currentState.Errors.FirstOrDefault(x => string.Compare(x.PropertyName, columnName, true) == 0);
return columnResults != null ? columnResults.ErrorMessage : string.Empty;
}
}
#endregion
}
这是Validator类:
public class CustomerDataContractValidator : AbstractValidator<CustomerDataContract>
{
private readonly ILanguageManager _languageManager = LanguageManager.Instance;
public CustomerDataContractValidator()
{
RuleFor(val => val.Lastname).NotEmpty().WithMessage(_languageManager.LanguageData["Global.Validation.ProvideLastname"]);
RuleFor(val => val.Firstname).NotEmpty().WithMessage(_languageManager.LanguageData["Global.Validation.ProvideFirstname"]);
RuleFor(val => val.Active).NotEmpty().WithMessage(_languageManager.LanguageData["Global.Validation.ProvideActive"]);
RuleFor(val => val.Gender).NotEmpty().WithMessage(_languageManager.LanguageData["Global.Validation.ProvideGender"]);
RuleFor(val => val.Mail).EmailAddress().When(val => !String.IsNullOrEmpty(val.Mail)).WithMessage(_languageManager.LanguageData["Global.Validation.ProvideValidEmail"]);
// At least one phone number has to be filled in order to contact the customer
RuleFor(val => val.MobilePhone).Must(CheckForAnyPhoneNumber).WithMessage(_languageManager.LanguageData["Global.Validation.ProvideAnyPhone"]);
RuleFor(val => val.OfficePhone).Must(CheckForAnyPhoneNumber).WithMessage(_languageManager.LanguageData["Global.Validation.ProvideAnyPhone"]);
RuleFor(val => val.PrivatePhone).Must(CheckForAnyPhoneNumber).WithMessage(_languageManager.LanguageData["Global.Validation.ProvideAnyPhone"]);
}
/// <summary>
/// Checks wheter or not any phone number has been provided
/// </summary>
/// <param name="customer">The customer</param>
/// <param name="phoneNumber">The phone number</param>
/// <returns></returns>
private static bool CheckForAnyPhoneNumber(CustomerDataContract customer, string phoneNumber)
{
return (!String.IsNullOrEmpty(customer.MobilePhone) || !String.IsNullOrEmpty(customer.OfficePhone) || !String.IsNullOrEmpty(customer.PrivatePhone));
}
}
验证助手:
public class ValidationHelper
{
public static ValidationResult Validate<T, K>(K entity)
where T : IValidator<K>, new()
where K : class
{
IValidator<K> validator = new T();
return validator.Validate(entity);
}
public static string GetError(ValidationResult result)
{
var errorMessage = "";
if (result != null)
{
var failure = result.Errors.FirstOrDefault();
if(failure != null)
{
errorMessage = failure.ErrorMessage;
}
}
return errorMessage;
}
}
ViewModel:
public class CustomerViewModel : BMovingSelectionViewModel, IEventListener, ICustomerViewModel
{
private CustomerDataContract _customer;
public CustomerDataContract Customer
{
get
{
return _customer;
}
set
{
if (_customer != value)
{
_customer = value;
OnPropertyChanged(() => Customer);
}
}
}
}
观点:
<TextBlock Text="{MarkupExtensions:LanguageManager Global.Person.PhoneOffice}" Grid.Row="3" Grid.Column="0" VerticalAlignment="Center" />
<TextBox Grid.Row="3" Grid.Column="1" Text="{Validation:ValidationBinding Path=Customer.OfficePhone}" HorizontalContentAlignment="Stretch" />
<TextBlock Text="{MarkupExtensions:LanguageManager Global.Person.PhonePrivate}" Grid.Row="4" Grid.Column="0" VerticalAlignment="Center" />
<TextBox Grid.Row="4" Grid.Column="1" Text="{Validation:ValidationBinding Path=Customer.PrivatePhone}" />
<TextBlock Text="{MarkupExtensions:LanguageManager Global.Person.PhoneMobile}" Grid.Row="5" Grid.Column="0" VerticalAlignment="Center" />
<TextBox Grid.Row="5" Grid.Column="1" Text="{Validation:ValidationBinding Path=Customer.MobilePhone}" />
答案 0 :(得分:0)
要使WPF更新错误信息,需要触发它才能执行此操作。该触发器是绑定属性上的PropertyChanged
事件。
最简单的解决方案是参与您的视图模型。如果您可以这样做,则只需要为依赖属性组中每个属性的setter中的所有依赖属性引发PropertyChanged
个事件。
这意味着设置PhoneOffice
会为PropertyChanged
,"PhoneOffice"
和"PhonePrivate"
提升"PhoneMobile"
。
另一种解决方案是使用规则集并将相关代码放入基类中。为了使其工作,需要执行以下步骤:
PropertyChanged
事件PropertyChanged