天天看點

[轉]使用ErrorProvider改善使用者體驗

1. ErrorProvider概述        

         我們經常使用Windows Forms下的ErrorProvider,這是一個.NET元件,可以在VS IDE的工具欄中找到它。Errorprovider通常用于窗體或控件的使用者輸入;同時它也是典型的關聯型(綁定)的驗證控件,用以驗證并顯示控件關聯的資料源如DataSet中存在的錯誤。ErrorProvider比使用消息框(MessageBox)顯示錯誤資訊的效果好,除了摘要中提到的情況外,還因為一旦消息框關閉了錯誤資訊也随之消失,使用者可能無法記憶所有的錯誤内容因而也就無法友善的糾正所有錯誤進而要多次彈出錯誤消息框。而 ErrorProvider會記錄所有的錯誤并能夠準确定位在錯誤發生的窗體或控件上,顯示一個紅色圖示,當滑鼠懸停在該圖示上方時還能夠自動彈出ToolTip提示以顯示錯誤内容。這樣操作人員可以根據錯誤發生的位置以及具體内容從容的修改錯誤,直到這些小圖示全部消失。

2. ErrorProvider屬性     

    ErrorProvider元件有三個關鍵的屬性:DataSource、ContainerControl和Icon。

  • DataSource通常與ContainerControl相關,也就是控件綁定的資料内容,可以是DataTable, DataSet或者自定義的實體等。ErrorProvider會根據DataSource的結構進行其内部的資料驗證,當然驗證的規則需要開發人員定 義。
  • ContainerControl正如其名字所言,正是ErrorProvider所依存的容器,通過為其設定适 當的容器,通常是Windows窗體,就是為了Errorprovider能夠在窗體上的适當位置顯示錯誤圖示。(不要忘了,ErrorProvider 是一個元件,凡是元件都具備相應的特征,其中很重要的一點就是容器的概念,如果你不清楚可以從MSDN上查閱有關元件的概念,請記住元件式的開發是微軟大 力推薦的一種開發規範,其實J2EE的規範中也處處展現這樣的思想。)
  • Icon屬性允許使用者自定義圖示。如果你對預設的這個小紅圓圈不滿意的話,沒關系,你可以通過該屬性用你自己的圖示替換。

3. ErrorProvider正常用法

        ErrorProvider的一種最簡單使用方法就是當使用者向某控件比如TextBox中輸入無效資料時顯示錯誤提示,這種情況下甚至不需要設定 DataSource,隻需要設定ContainerControl屬性值為目前Form并使用SetError方法進行簡單編碼即可,如下所示。

protected void textBox1_Validating (object sender,

   System.ComponentModel.CancelEventArgs e)

{

   try

   {

      int x = Int32.Parse(textBox1.Text);

      errorProvider1.SetError(textBox1, "");

   }

   catch (Exception e)

      errorProvider1.SetError(textBox1, "Not an integer value.");

}

        在窗體上一個TextBox控件的驗證事件處理方法中我們檢查使用者填入内容是否是數值,如果不是則在該TextBox控件旁顯示錯誤圖示,相應的 ToolTip文本就是“Not an integer value”。從另外一個角度,我們也可以猜到如果要手工消除錯誤資訊,也是通過SetError方法将提示文本設為空字元串即可。

         實際上,ErrorProvider元件也可以捕獲到DataSet或其他資料源的列上出現的錯誤,也就是說一旦将ErrorProvider綁定到資料源,不必直接關聯到控件就可以在綁定相同資料源的控件上顯示錯誤圖示,代碼如下。

  • 将ErrorProvider元件綁定到一個DataTable的某一列上(使用DataSource和DataMember屬性)

          textBox1.DataBindings.Add("Text", DataSet1, "Customers.Name");

         errorProvider1.DataSource = DataSet1;

          errorProvider1.DataMember = "Customers";

  • 設定Errorprovider的ContainerControl屬性
         errorProvider1.ContainerControl = this;
  • 設定包含一個列錯誤的某一行的位置

         DataTable1.Rows[5].SetColumnError("Name", "Bad data in this row.");//Name是列名,後面是錯誤提示

         this.BindingContext [DataTable1].Position = 5;//發生錯誤的行是Table的第五行,ErrorProvider綁定這一行

4. ErrorProvider的實體綁定機制

         上面列舉的ErrorProvider的用法都是最基本的,不用編碼或者隻需少量編碼或者設定一些相關的屬性就能夠實作一定的功能,然而這些實作方式對于一個相當規模的系統而言擴充性非常有限,不夠靈活,而且沒有與系統架構緊密結合起來。事實上,大多數情況下我們的系統具有嚴格的分層,其中不乏有O/RMapping。當在前台界面上作資料儲存、更新時往往會涉及到對底層實體的操作。實體裝載的資料是否滿足業務規則,是否滿足資料庫定義的要求應當能夠反映在前台的界面上。這樣一個從上層(UI層)送出資料給下層(業務層、實體層)到從下層回報錯誤資訊給上層的過程也可以利用 ErrorProvider提供的便利。我們完全可以建構一套完整的資料綁定機制,當實體層發生資料錯誤時在界面上的ErrorProvider可以及時感覺到并顯示出來。這也就是所謂的智能感覺,當然除了ErrorProvider還需要bindingsource元件的支援。如下圖所示。

在系統界面上我們可以看到接受使用者輸入資訊的控件都有一個DataBindings屬性目錄,其中又包含三個具體的控件屬性項分别是Advanced、Tag、Text,如下圖所示。

點選"進階"(Advanced)項,彈出一個資料綁定對話框,右邊的條目分别用以設定該控件綁定資料源的字段,資料源發生更新的模式以及該控件錄入資訊必須滿足的格式類型,如下圖所示。

         對于智能感覺而言,資料源更新模式項非常重要,Never條目表明不提示資料源更新;OnPropertyChanged表明當資料源屬性發生改變時提示資料源更新,使用者可以看到窗體界面的左上角窗體标題的後面多出一個"*"号,操作儲存或放棄後該星号消失; OnValidation表明當資料驗證時提示資料源更新。(關于智能感覺的部分不是本文介紹的重點,請參見MSDN相關文檔。)同樣對于錯誤提示而言也有兩種情況,一種是當使用者在界面控件上輸入不符合規則的資料後立刻提示錯誤,另一種是使用者點選儲存或更新按鈕動作後再進行資料驗證并在界面上顯示錯誤資訊,兩種方式都是通過ErrorProvider實作的,這裡重點讨論第二種方式。

      為了讓ErrorProvider能夠感覺到資料源内部發生的錯誤,資料實體應至少繼承兩個接口 INotifyPropertyChanged和IDataErrorInfo。這兩個接口都位于System.ComponentModel命名空間下,前者提供了一個屬性改變事件PropertyChanged,繼承的實體内每個簡單屬性都應該引發該事件以便外部捕獲到屬性值的改變;後者提供了一個錯誤資訊清單Error用以自定義錯誤資訊,也就是ToolTip要顯示的内容,還有一個索引器用以根據列名擷取對應的錯誤資訊。通常情況下,我們都會為所有的實體定義一個基類,該基類繼承上述接口,實作相應的屬性,另外為友善起見還會新增一個IsValid屬性以表明派生的實體類目前屬性是否通過驗證。

       需要注意的是,這裡關于Error屬性的設定也存在兩種方式,一種是在實體内部定義業務驗證規則,将每個屬性必須滿足的規則定義好以及将發生錯誤時生成的錯誤資訊定義好以便填充到Error屬性中。但是這種方法存在一個很嚴重的缺陷就是業務規則與實體實作緊耦合不友善移植和擴充。另一種辦法就是在實體基類中定義一個公共方法專門用以為每個屬性設定錯誤資訊,這樣我們就可以在業務層進行資料校驗時将對應錯誤資訊寫入到該實體的錯誤清單中。