这是TextBox:如何实现? 解决方案 这实际上取决于您对 IDataErrorInfo 的实现.如果您以错误消息字典为基础,则可以控制添加到该列表的验证运行的时间.您通常希望从您的属性设置器中执行此操作(例如每次调用 PropertyChange 时),此处调用 CheckValidationState: public string this[string columnName]{得到{返回 ValidateProperty(columnName);}}公共字典错误 { 得到;私人订制;}protected void SetError(string propertyName, string errorMessage){Debug.Assert(!String.IsNullOrEmpty(propertyName), "propertyName 为空或空.");if (String.IsNullOrEmpty(propertyName))返回;if (!String.IsNullOrEmpty(errorMessage)){if (Errors.ContainsKey(propertyName))错误[propertyName] = errorMessage;别的Errors.Add(propertyName, errorMessage);}else if (Errors.ContainsKey(propertyName))Errors.Remove(propertyName);NotifyPropertyChanged("错误");NotifyPropertyChanged("错误");NotifyPropertyChanged("Item[]");}受保护的虚拟字符串 ValidateProperty(string propertyName){返回 Errors.ContainsKey(propertyName) ?错误[属性名称]:空;}protected virtual bool CheckValidationState(string propertyName, T proposalValue){//你的验证逻辑在这里}然后,您还可以包含一个方法来验证您的所有属性(例如在保存期间): protected bool Validate(){if (Errors.Count > 0)返回假;布尔结果 = 真;foreach (PropertyInfo propertyInfo in GetType().GetProperties()){if (!CheckValidationState(propertyInfo.Name, propertyInfo.GetValue(this, null)))结果=假;NotifyPropertyChanged(propertyInfo.Name);}返回结果;}更新:我建议将上述代码放入基础 ViewModel 类中,以便您可以重用它.然后你可以像这样创建一个派生类: 公共类 SampleViewModel : ViewModelBase{私人字符串_firstName;公共 SampleViewModel(){Save = new DelegateCommand(SaveExecuted);}公共委托命令保存{得到;私人订制;}公共字符串名字{得到 { 返回 _firstName;}放{如果(_firstName == 值)返回;CheckValidationState("FirstName", value);_firstName = 值;NotifyPropertyChanged("名字");}}公共无效保存执行(对象对象){bool isValid = Validate();MessageBox.Show(isValid ? "Saved" : "验证错误.取消保存");//TODO:在这里做一些适合你的应用的事情}protected override bool CheckValidationState(string propertyName, T proposalValue){//你的验证逻辑在这里if (propertyName == "FirstName"){if (String.IsNullOrEmpty(proposedValue as String)){SetError(propertyName, "First Name is required.");返回假;}else if (proposedValue.Equals("John")){SetError(propertyName, "\"John\" 不是一个允许的名字.");返回假;}别的{SetError(propertyName, String.Empty);//清除错误返回真;}}返回真;}}在这种情况下,我使用 DelegateCommand 来触发保存操作,但它可以是任何调用方法来执行保存的操作.此设置允许初始空状态在 UI 中显示为有效,但更改或调用 Save 会更新验证状态.您还可以在实际进行验证的方式中获得更通用和更复杂的方法,因此它不会全部以一种方法结束(这里有一些关于类型的假设)但这是简化的,以便更容易开始.I have validation hooked up to a model that is bound to the TextBox container. When the window is first opened validation errors appear as the model is empty, I do not want to see validation errors until submit of the window or the text in the TextBox has changed or on lost focus.Here is the TextBox:<TextBox Text="{Binding Path=Firstname, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" Width="124" Height="24"/>How can this be achieved? 解决方案 This really depends on your implementation of IDataErrorInfo. If you base it around a Dictionary of error messages you can control when validation runs that adds to that list. You would normally want to do that from your property setters (like whenever you call PropertyChange), here calling CheckValidationState: public string this[string columnName] { get { return ValidateProperty(columnName); } } public Dictionary<string, string> Errors { get; private set; } protected void SetError(string propertyName, string errorMessage) { Debug.Assert(!String.IsNullOrEmpty(propertyName), "propertyName is null or empty."); if (String.IsNullOrEmpty(propertyName)) return; if (!String.IsNullOrEmpty(errorMessage)) { if (Errors.ContainsKey(propertyName)) Errors[propertyName] = errorMessage; else Errors.Add(propertyName, errorMessage); } else if (Errors.ContainsKey(propertyName)) Errors.Remove(propertyName); NotifyPropertyChanged("Errors"); NotifyPropertyChanged("Error"); NotifyPropertyChanged("Item[]"); } protected virtual string ValidateProperty(string propertyName) { return Errors.ContainsKey(propertyName) ? Errors[propertyName] : null; } protected virtual bool CheckValidationState<T>(string propertyName, T proposedValue) { // your validation logic here }You can then also include a method that validates all of your properties (like during a save): protected bool Validate() { if (Errors.Count > 0) return false; bool result = true; foreach (PropertyInfo propertyInfo in GetType().GetProperties()) { if (!CheckValidationState(propertyInfo.Name, propertyInfo.GetValue(this, null))) result = false; NotifyPropertyChanged(propertyInfo.Name); } return result; }UPDATE:I would recommend putting the above code into a base ViewModel class so you can reuse it. You could then create a derived class like this:public class SampleViewModel : ViewModelBase{ private string _firstName; public SampleViewModel() { Save = new DelegateCommand<object>(SaveExecuted); } public DelegateCommand<object> Save { get; private set; } public string FirstName { get { return _firstName; } set { if (_firstName == value) return; CheckValidationState("FirstName", value); _firstName = value; NotifyPropertyChanged("FirstName"); } } public void SaveExecuted(object obj) { bool isValid = Validate(); MessageBox.Show(isValid ? "Saved" : "Validation Error. Save canceled"); // TODO: do something appropriate to your app here } protected override bool CheckValidationState<T>(string propertyName, T proposedValue) { // your validation logic here if (propertyName == "FirstName") { if (String.IsNullOrEmpty(proposedValue as String)) { SetError(propertyName, "First Name is required."); return false; } else if (proposedValue.Equals("John")) { SetError(propertyName, "\"John\" is not an allowed name."); return false; } else { SetError(propertyName, String.Empty); // clear the error return true; } } return true; }}In this case I'm using a DelegateCommand to trigger the save operation but it could be anything that makes a method call to do the saving. This setup allows for the initial empty state to show up as valid in the UI but either a change or a call to Save updates the validation state. You can also get a lot more general and more complicated in the way you actually do the validation so it doesn't all end up in one method (here with some assumptions about the type) but this is simplified to make it easier to start with. 这篇关于WPF 文本框验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!
06-08 20:27