WPF/C#:BusinessLayerValidation

mingupupup發表於2024-06-25

BusinessLayerValidation介紹

BusinessLayerValidation,即業務層驗證,是指在軟體應用程式的業務邏輯層(Business Layer)中執行的驗證過程。業務邏輯層是應用程式架構中的一個關鍵部分,負責處理與業務規則和邏輯相關的操作。業務層驗證的主要目的是確保資料在業務規則和邏輯上的有效性,從而維護資料的完整性和一致性。

  • 業務層驗證的主要目的是確保資料在業務規則和邏輯上的有效性。這包括檢查資料是否符合特定的業務規則、資料完整性檢查、資料一致性檢查等。
  • 透過在業務層進行驗證,可以確保資料在整個應用程式中的正確性和一致性,而不僅僅是在使用者介面層。

在WPF中如何實現BusinessLayerValidation

在WPF Samples中有一個Demo提到了BusinessLayerValidation。

該Demo結構如下所示:

image-20240625143242336

實現的效果如下所示:

當輸入值是字元時會提示不是正確的形式,當輸入小於0或大於150的數時會有一個自定義的提示。

IDataErrorInfo介面

在WPF中實現業務邏輯層的驗證可以使用IDataErrorInfo介面與INotifyDataErrorInfo 介面。這個Demo使用的是IDataErrorInfo介面。IDataErrorInfo介面主要用於在資料繫結場景中提供自定義的驗證錯誤資訊。IDataErrorInfo介面包含兩個成員:

string IDataErrorInfo.Error { get; }

這個屬性返回一個字串,表示整個物件的錯誤資訊。如果物件沒有錯誤,應該返回一個空字串或null。

string IDataErrorInfo.this[string columnName] { get; }

這個索引器用於返回指定屬性的錯誤資訊。columnName參數列示屬性的名稱,索引器應該返回該屬性的錯誤資訊。如果屬性沒有錯誤,應該返回一個空字串或null。

透過實現IDataErrorInfo介面,可以為資料物件提供詳細的驗證錯誤資訊,這些資訊可以在使用者介面中顯示,幫助使用者理解和糾正輸入錯誤。

定義一個實現該介面的Person類:

 public class Person : IDataErrorInfo
 {
     public int Age { get; set; }
     public string Error => null;

     public string this[string name]
     {
         get
         {
             string result = null;

             if (name == "Age")
             {
                 if (Age < 0 || Age > 150)
                 {
                     result = "Age must not be less than 0 or greater than 150.";
                 }
             }
             return result;
         }
     }
 }

定義資源

  <local:Person x:Key="Data"/>

現在xaml中定義了一個Person物件為資源,鍵名為Data。

<!--The tool tip for the TextBox to display the validation error message.-->
<Style x:Key="TextBoxInError" TargetType="TextBox">
    <Style.Triggers>
        <Trigger Property="Validation.HasError" Value="true">
            <Setter Property="ToolTip"
                    Value="{Binding RelativeSource={x:Static RelativeSource.Self},
                                    Path=(Validation.Errors)[0].ErrorContent}"/>
        </Trigger>
    </Style.Triggers>
</Style>

為TextBox控制元件定義了一個鍵名為TextBoxInError的樣式(Style)。

觸發器(Trigger)

在WPF中,觸發器(Trigger)是一種用於在特定條件滿足時改變控制元件外觀或行為的機制。Trigger通常用於Style

或ControlTemplate中,以便在屬性值變化或事件發生時自動應用視覺效果或行為。

WPF 中的Trigger可以分為以下幾類:

  • Property Trigger
  • Data Trigger
  • Event Trigger
  • MultiTrigger
  • MultiDataTrigger

Property Trigger是最常用的觸發器型別。它根據依賴屬性的值來應用視覺效果或行為。

示例:

<Style TargetType="Button">
  <Style.Triggers>
    <Trigger Property="IsMouseOver" Value="True">
      <Setter Property="Background" Value="Yellow"/>
    </Trigger>
  </Style.Triggers>
</Style>

在這個例子中,當滑鼠懸停在按鈕上時,按鈕的背景色會變為黃色。

Data Trigger類似於Property Trigger,但它用於繫結資料上下文中的屬性,而不是控制元件本身的依賴屬性。

示例:

<Style TargetType="TextBlock">
  <Style.Triggers>
    <DataTrigger Binding="{Binding Path=IsEnabled}" Value="False">
      <Setter Property="Foreground" Value="Gray"/>
    </DataTrigger>
  </Style.Triggers>
</Style>

在這個例子中,當資料上下文中的IsEnabled屬性為False時,文字塊的前景色會變為灰色。

Event Trigger用於在特定事件發生時執行動畫或命令。

示例:

<Button Content="Click Me">
  <Button.Triggers>
    <EventTrigger RoutedEvent="Button.Click">
      <BeginStoryboard>
        <Storyboard>
          <DoubleAnimation Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="0:0:1"/>
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
  </Button.Triggers>
</Button>

在這個例子中,當按鈕被點選時,按鈕的透明度會從 1 變為 0,持續 1 秒鐘。

MultiTriggerMultiDataTrigger允許你指定多個條件,只有當所有條件都滿足時,才會應用視覺效果或行為。

示例:

<Style TargetType="TextBox">
  <Style.Triggers>
    <MultiTrigger>
      <MultiTrigger.Conditions>
        <Condition Property="IsFocused" Value="True"/>
        <Condition Property="Text" Value=""/>
      </MultiTrigger.Conditions>
      <Setter Property="BorderBrush" Value="Red"/>
    </MultiTrigger>
  </Style.Triggers>
</Style>

在這個例子中,當文字框獲得焦點且文字為空時,文字框的邊框顏色會變為紅色。

透過使用這些觸發器,可以建立動態和響應式的使用者介面,根據不同的條件自動調整控制元件的外觀和行為。

透過回顧WPF中的這些觸發器,再來看看現在遇到的觸發器:

 <Style.Triggers>
        <Trigger Property="Validation.HasError" Value="true">
            <Setter Property="ToolTip"
                    Value="{Binding RelativeSource={x:Static RelativeSource.Self},
                                    Path=(Validation.Errors)[0].ErrorContent}"/>
        </Trigger>

這是屬性觸發器,當Validation.HasError屬性的值為true時,會將ToolTip的值設定為(Validation.Errors)[0].ErrorContent的值。

之前我們已經接觸過StaticSource這表示是靜態資源,現在這裡是RelativeSource,讓我們來了解一下它吧。

RelativeSource是WPF中的一個繫結標記擴充套件,用於指定資料繫結的源相對於繫結目標的位置。它允許你在繫結表示式中引用相對於當前控制元件或資料上下文的另一個物件,而不是直接指定一個固定的源物件。

RelativeSource可以用於以下幾種模式:

  • Self:繫結到控制元件自身的一個屬性。
  • TemplatedParent:繫結到應用控制元件模板的控制元件。
  • PreviousData:在資料模板中繫結到前一個資料項。
  • FindAncestor:繫結到可視樹中的祖先控制元件。

可以建立更靈活和動態的資料繫結,特別是在處理複雜的使用者介面和控制元件模板時。

再來看文字框部分:

 <StackPanel Margin="20">
     <TextBlock>Enter your age:</TextBlock>
     <TextBox Style="{StaticResource TextBoxInError}">
         <TextBox.Text>
             <!--By setting ValidatesOnExceptions to True, it checks for exceptions
             that are thrown during the update of the source property.
             An alternative syntax is to add <ExceptionValidationRule/> within
             the <Binding.ValidationRules> section.-->
             <Binding Path="Age" Source="{StaticResource Data}"
                      ValidatesOnExceptions="True"
                      UpdateSourceTrigger="PropertyChanged">
                 <Binding.ValidationRules>
                     <!--DataErrorValidationRule checks for validation 
                         errors raised by the IDataErrorInfo object.-->
                     <!--Alternatively, you can set ValidationOnDataErrors="True" on the Binding.-->
                     <DataErrorValidationRule/>
                 </Binding.ValidationRules>
             </Binding>
         </TextBox.Text>
     </TextBox>
     <TextBlock>Mouse-over to see the validation error message.</TextBlock>
 </StackPanel>

首先為文字框設定了鍵名為TextBoxInError的樣式。

 <TextBox.Text>   
 <Binding Path="Age" Source="{StaticResource Data}"
          ValidatesOnExceptions="True"
          UpdateSourceTrigger="PropertyChanged">
      <Binding.ValidationRules>
                 <DataErrorValidationRule/>
      </Binding.ValidationRules>
             </Binding>
  </TextBox.Text>

ValidatesOnExceptions屬性指定了是否在資料繫結過程中捕獲並處理異常。ValidatesOnExceptions="True"

表示如果在資料繫結過程中發生了異常(例如,資料來源的Age屬性在設定值時丟擲了異常),這個異常將會被捕獲並用於驗證目的,通常用於顯示錯誤資訊或阻止無效資料的輸入。

  <Binding.ValidationRules>
        <DataErrorValidationRule/>
  </Binding.ValidationRules>

Binding.ValidationRules是一個集合屬性,用於儲存資料繫結的驗證規則。這些驗證規則用於在資料繫結過程中檢查資料的合法性。DataErrorValidationRule是WPF中預定義的一種驗證規則。它用於檢查資料物件是否實現了

IDataErrorInfo介面,並根據該介面提供的資訊進行驗證。當資料物件實現了IDataErrorInfo介面時,DataErrorValidationRule會呼叫介面中的方法來獲取錯誤資訊,並在資料繫結過程中應用這些錯誤資訊。

驗證型別

預設驗證:當你輸入 "a" 時,WPF嘗試將 "a" 轉換為整數,但由於 "a" 不是有效的整數,預設驗證機制會生成一個錯誤,提示 "不是正確的格式"。

自定義驗證:在你輸入一個有效的整數後,WPF會繼續檢查這個值是否符合你的自定義驗證規則(例如,年齡必須在0到150之間)。如果值不符合規則,你會看到 "Age must not be less than 0 or greater than 150" 的提示。

在WPF中,資料繫結的驗證過程通常遵循以下順序:

資料轉換(Data Conversion)

如果繫結的資料需要從一種型別轉換為另一種型別(例如,從字串轉換為整數),WPF會首先嚐試進行型別轉換。如果轉換失敗,會丟擲一個異常,這個異常可以被捕獲並用於驗證目的。

驗證規則(Validation Rules)

如果繫結的ValidationRules集合中定義了任何自定義的驗證規則,WPF會按照這些規則的順序依次執行它們。每個驗證規則可以返回一個ValidationResult物件,指示資料是否有效以及相關的錯誤資訊。

異常驗證(Exception Validation)

如果繫結的ValidatesOnExceptions屬性設定為True,WPF會在資料繫結的過程中捕獲任何丟擲的異常,並將這些異常轉換為驗證錯誤。這通常用於捕獲資料轉換或資料設定過程中的異常。

IDataErrorInfo 驗證

如果資料物件實現了IDataErrorInfo介面,WPF會呼叫該介面的方法來獲取錯誤資訊。DataErrorValidationRule

可以用於在資料繫結過程中應用這些錯誤資訊。

INotifyDataErrorInfo 驗證

如果資料物件實現了INotifyDataErrorInfo介面,WPF會監聽該介面的事件,並在資料發生錯誤時獲取錯誤資訊。這種驗證方式提供了更靈活和非同步的驗證機制。

這些驗證步驟並不是嚴格按順序執行的,而是根據繫結的配置和資料物件的實現情況來決定。例如,如果繫結的

ValidationRules集合中包含了DataErrorValidationRule,那麼IDataErrorInfo驗證會在驗證規則執行的過程中被觸發。

WPF中的驗證順序是靈活的,並且可以根據具體的繫結配置和資料物件的實現情況來調整。通常情況下,資料轉換和自定義驗證規則會在異常驗證和IDataErrorInfo驗證之前執行。

程式碼來源

[WPF-Samples/Data Binding/BusinessLayerValidation at main · microsoft/WPF-Samples (github.com)](https://github.com/microsoft/WPF-Samples/tree/main/Data Binding/BusinessLayerValidation)

相關文章