WPF的表單驗證,天然比不上WEB多姿多彩。通常有三種方式進行表單驗證:this
1. 代碼直接驗證(很多人直接用 MessageBox 彈出消息,Windows 的老傳統),雖然夠醒目,卻太過打擾用戶,很差。spa
2. 經過異常驗證(數據綁定,並設置 ValidatesOnExceptions=True ),調試時煩死人,很差。.net
3. 經過內置接口 IDataErrorInfo 、INotifyDataErrorInfo 進行驗證(數據綁定),這應該是目前較爲理想的驗證方式。這兩個接口都位於 System.ComponentModel 空間,與 INotifyPropertyChanged 在一塊兒。調試
只說第三種驗證方式。code
這兩個接口,我的較喜歡第二個,緣由是第一個接口不太靈活,並且是爲了兼容而存在的,不推薦使用。第二要靈活得多。blog
爲了突出驗證消息的提示效果,可添加這樣一個樣式(定義爲字典資源,用起來更方便):接口
<Style TargetType="TextBox"> <Setter Property="Validation.ErrorTemplate"> <Setter.Value> <ControlTemplate> <DockPanel> <TextBlock DockPanel.Dock="Bottom" Foreground="Red" Text="{Binding ElementName=adornedElement, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}"></TextBlock> <Border BorderBrush="Red" BorderThickness="1"> <AdornedElementPlaceholder Name="adornedElement"></AdornedElementPlaceholder> </Border> </DockPanel> </ControlTemplate> </Setter.Value> </Setter> </Style>
1、首先定義一個集合,用於保存驗證消息:事件
private readonly IDictionary<string, IList<string>> m_errors = new Dictionary<string, IList<string>>();
2、下面是實現接口,具體用法見註釋:資源
// 該方法僅爲簡化屬性調用。CallerMemberName 特性是 .net 4.5 才加入的,位於 System.Runtime.CompilerServices 空間。
public void Validate(Func<bool> valid, string error, [CallerMemberName]string prop = null) { if (valid()) ClearError(prop); else SetError(new[] { error }, prop); OnChanged(prop); }
// 驗證屬性事件。
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged; // 屬性更改事件。 public event PropertyChangedEventHandler PropertyChanged; // 該方法由 wpf 調用。 public IEnumerable GetErrors(string propertyName) { if (string.IsNullOrEmpty(propertyName)) return null; // SelectMany 方法頗有用,若沒有它,錯誤消息不能正確顯示,除非你重寫集合,並重寫其 ToString 方法。它幫你省了不少麻煩。 var errors = m_errors.SelectMany(e => e.Value); return errors; } // 添加錯誤消息。 public void SetError(IList<string> errors, string prop) { m_errors.Remove(prop); m_errors.Add(prop, errors); OnError(prop); } // 清除錯誤消息。 public void ClearError(string prop) { m_errors.Remove(prop); OnError(prop); } // 驗證屬性時調用。 private void OnError(string prop) { ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(prop)); }
3、屬性這樣調用驗證代碼(以及更新事件):get
public string Password
{
get { return m_password; }
set
{
m_password = value;
// 因爲第三種驗證方式比較溫和,不能像異常那樣阻止屬性值更新,所以該方法放在下面沒有問題。
Validate(() => !Regex.IsMatch(value, "4"), "數字 4 不祥");
}
}
4、前臺代碼並無什麼特殊的,只要你別忘了應用上面的樣式。 ValidatesOnNotifyDataErrors=True 可不寫,但建議寫上,有提示做用:
<TextBox Text="{Binding Path=Password, ValidatesOnNotifyDataErrors=True}"></TextBox>
完。