簡體   English   中英

如何在WinForms中的數據綁定控件上覆蓋錯誤消息?

[英]How do I override the error message on a databound control in WinForms?

我的應用程序中有一個表單,該表單使用綁定源將控件綁定到模型對象。 這樣可以正常工作並處理基本驗證,例如確保用戶沒有在數字字段中輸入文本。 我正在使用ErrorProvider,並設置其datasource =綁定源,以便向用戶顯示錯誤消息,並且效果也不錯。

但是,我在弄清兩件事時遇到了麻煩:

  1. 如何以對最終用戶更直觀的方式覆蓋默認錯誤消息。 例如,上述情況下的默認消息是:“輸入字符串的格式不正確”,而我希望它說一些類似的信息:“年齡必須為正整數”。

  2. 如何使用更復雜的業務邏輯輕松擴展此系統。 例如,上面的默認處理程序將阻止接受字符串作為數字,但是默認情況下不會強制年齡大於0。 我知道我可以為每個控件覆蓋onValidate,但似乎應該有一個更簡單的方法,它依賴於數據模型,而不是單個控件。

我嘗試按如下方式更新我的設置器,希望該消息隨后顯示在使用此模型對象的所有表單/綁定上,但這不起作用:

Public Property Age() As Integer
  Get
    Return m_age
  End Get
  Set(ByVal Value As Integer)
    If Not IsNumeric(Value) And Value > 0 Then
      Throw New ArgumentException("Age must be a positive integer.")
    End If
    m_age = Value
  End Set
End Property

還有其他想法嗎?

因此,據我所知,這幾乎是可能的,但是由於某些錯誤行為,無法像您希望的那樣簡單。 問題源於格式化程序和類型轉換程序吞噬/覆蓋域對象的錯誤消息這一事實。

這與我所得到的差不多:

對於域對象,您要綁定到:

  • 實現System.ComponentModel.IDataErrorInfo ,返回所需的用戶友好消息。
  • 實現INotifyPropertyChanged以警告更改的綁定源。

將ErrorProvider.DataSource設置為BindingSource。

為要覆蓋默認轉換錯誤消息的每個文本字段的Validating事件添加一個處理程序。

手動為控件添加綁定,以便您可以關閉格式設置。 如果您不這樣做,那么格式化程序將吃掉您提供的任何自定義錯誤消息。 因此,請勿在VS中使用屬性編輯器。 而是分配綁定ala:

TextBox1.DataBindings.Add("Text", BindingSource1, "Age", False, DataSourceUpdateMode.OnValidation)

如果執行上述操作,則最終用戶將正確看到模型對象的錯誤消息,只要轉換沒有引起錯誤即可。 如果轉換導致錯誤,則他們將看到您在Validating處理程序中提供的消息(如果有的話),否則將看到常規消息。

仍然不是一個理想的解決方案,但這與我所能達到的接近。 我說不太理想,因為此解決方案無法使用自動格式設置,並且如果您在多個位置使用模型對象,則要求您以不同的形式復制某些驗證消息。

這里。 這應該為您節省大量的工作。

簡而言之:要驗證綁定控件,您需要處理三個事件。

  • Control.Validating事件,它在用戶離開控件時驗證數據,
  • Control.Validated事件,該事件僅在經過正確驗證后才更新數據源,並且
  • Binding.Parse事件,當其他任何事情更改控件中的數據(即您的代碼)時,該事件將驗證數據。

為了確保僅將有效數據寫入數據源,在創建Binding時將關閉對綁定數據的自動更新-這樣, Control.Validated事件期間將數據寫入數據源。

Validating事件和Parse事件都將驗證錯誤消息放入附加到綁定ControlErrorProvider 您可能還想通過其他方式顯示錯誤消息,在這種情況下,您需要同時更改這兩個事件。

您可能還需要處理綁定的Format事件,以控制如何在綁定控件中顯示字段中的數據。

我沒有重寫此代碼以使其通用,因為我不想引入任何錯誤。 因此,我將解釋fccm是什么,只要您需要知道使其起作用即可。

fc是包裝我的應用程序的綁定Control對象的類的實例。 它具有一個Control屬性(顯然是包裝的控件),然后是BindingErrorProvider屬性,其用法如下所示。 請注意,由於此代碼為您設置了數據綁定,因此您無需在表單設計器中設置控件的綁定。 嚴格來說,您不需要此類就可以使此代碼正常工作,但是確實可以簡化代碼。 (這里的所有代碼均來自BindingSource已傳遞到的fc類上的靜態方法,如圖所示。)

cm是一個類的實例,該類包含有關將控件綁定到的數據列的元信息,尤其是:

  • ColumnName ,它在數據源中的名稱(我顯然是綁定到DataColumn ),
  • PropertyName ,它綁定到的控件屬性的名稱(例如"Text" ),
  • NullValue ,如Binding.NullValue文檔中Binding.NullValue
  • Format ,格式化列內部值以在綁定控件中顯示的方法,以及
  • Parse ,用於將輸入解析為列的內部值的方法。 列的實際驗證邏輯位於此處。

顯然,這是C#,因此您需要弄亂它才能使其在VB中工作,但是區別應該只是語法問題。

 // add an ErrorProvider to the control so that we have a place to display
 // error messages
 fc.ErrorProvider = new ErrorProvider {BlinkStyle = ErrorBlinkStyle.NeverBlink};

 // create the Binding.  DataSourceUpdateMode.Never bypasses automatic updating
 // of the data source; data only gets written to the data source when the
 // column is successfully validated.
 fc.Binding = fc.Control.DataBindings.Add(
    cm.PropertyName,
    bindingSource,
    cm.ColumnName,
    true,
    DataSourceUpdateMode.Never,
    cm.NullValue);

 // this is called whenever the Binding pushes data back to the data source;
 // it parses the data in the control into an object that's returned in e.Value.
 fc.Binding.Parse += delegate(object sender, ConvertEventArgs e)
 {
     string property = fc.Binding.PropertyName;
     object unparsedValue = fc.Control.GetType().GetProperty(property).GetValue(fc.Control, null);

     string message;
     // note that we don't actually care about the parsed value if message
     // is not null (i.e. if the value is invalid).  by convention it's null,
     // but it won't ever get written back to the data source.
     object parsedValue = cm.Parse(unparsedValue, out message);
     if (message != null)
     {
         fc.ErrorProvider.SetError(fc.Control, message);
     }
     else
     {
         fc.ErrorProvider.Clear();
     } 
     e.Value = parsedValue ?? DBNull.Value;
  };

  // this is called whenever the user leaves the Control.
  fc.Control.Validating += delegate
                                     {
     string property = fc.Binding.PropertyName;
     object value = fc.Control.GetType().GetProperty(property).GetValue(fc.Control, null);
     string message;
     cm.Parse(value, out message);
     if (message != null)
     {
         fc.ErrorProvider.SetError(fc.Control, message);
     }
     else
     {
         fc.ErrorProvider.Clear();
     }
 };

 // this, combined with the DataSourceUpdateMode of Never, insures that the Control's
 // value only gets pushed out to the data source after validation is successful.
 fc.Control.Validated += delegate {
     fc.Binding.WriteValue();
 };

 // this is called whenever the Binding pulls data from the data source into 
 // the bound Control
 fc.Binding.Format += delegate(object sender, ConvertEventArgs e)
 {
     e.Value = cm.Format(e.Value);
 };

將錯誤返回給調用方。 然后,捕獲要“覆蓋”的異常類型。 與其顯示該異常消息,不如拋出一個自定義異常並顯示其消息。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM