使用 Service Manager 撰寫工具自定義和撰寫表單的概觀

重要

此版本的 Service Manager 已達到終止支援。 建議您升級至 Service Manager 2022

表單是讓使用者能與來自資料庫之物件互動的視窗。 使用者可使用表單來檢視和編輯物件的內容。 每個表單都與特定的類別連結,它只會顯示目標類別之執行個體的資訊。 表單包含多個欄位。 一般而言,每個欄位都會系結至窗體目標類別的特定屬性。 例如,事件表單與事件物件繫結。 因此,事件表單會顯示資料庫中事件物件的相關資訊。

Service Manager 表單包含 Microsoft .NET Framework 元件中的 Windows Presentation Foundation (WPF) 表單實作,以及 Service Manager 管理元件中的表單定義。 表單定義可指定表單呈現的類別,以及表單的其他內容。

表單的重要概念

在自訂表單之前,您應該要熟悉下列表單概念。

表單的使用方式

當包含表單定義的管理元件匯入 Service Manager 時,表單定義會儲存在資料庫中。 稍後,當使用者起始需要顯示物件的 Service Manager 控制台工作時,Service Manager 必須尋找窗體以顯示要求的物件。 Service Manager 存取資料庫,並搜尋已針對該物件定義的表單。 如果未為物件定義任何表單,Service Manager 搜尋針對物件的父物件所定義的表單。 Service Manager 會繼續搜尋整個物件的繼承階層,直到找到已定義的表單為止。

泛型表單

如果 Service Manager 找不到物件的任何窗體或其任何父物件的任何表單,Service Manager 會動態建置該物件的默認泛型表單。 一般表單是系統產生的表單,其功用應足以滿足簡單的表單用途。 一般表單代表在不使用表單定義的情況下建立物件之表單的快速、簡易方法。

根據預設,泛型窗體會在您無法變更的簡單版面配置中顯示表單的所有屬性。 泛型窗體會顯示窗體繼承階層中所有父對象的屬性,而且您無法變更該行為。 一般表單的自訂是有限的。 例如,您可以指定要顯示泛型表單的屬性;不過,泛型窗體無法做為自定義的基礎。 如果您稍後為該物件定義自定義表單,則自定義窗體會覆寫物件的泛型表單。

如需隱藏一般表單之內容,以及一般表單之其他自訂方法的相關資訊,請參閱部落格文章 Overview of the Forms Infrastructure and the Generic Form (表單基礎結構和一般表單概觀)

表單中的組合類別

在某些情況下,您需要表單顯示由多個類別衍生而來的資訊。 若要這樣做,您需要建立「 組合類別 」,然後再使表單中的欄位與組合類別繫結。 如需組合類別的詳細資訊,請參閱 System Center 通用架構的變更

表單的功能層面

表單的功能層面可分為以下幾種:

  1. 初始化

  2. 大小和位置

  3. 重新整理

  4. 提交變更

以下小節含有這些層面的描述。

初始化

在初始化期間,會剖析表單的Extensible Application Markup Language (XAML) ,並且會具現化和載入窗體上的所有控件。 表單的 Loaded 事件會指出表單和所有內含元素的載入時機。 資料載入作業是非同步的, 因此當 Loaded 事件發生時,目標執行個體可能會無法使用。 反之,如果表單的目標執行個體已設定,必須使用 DataContextChanged 事件來進行通知。 PropertyChanged 內容的 DataContext 事件可用來取代 DataContextChanged 事件。

我們建議您將 Loaded 事件用於控制項相關的自訂初始化,將 DataContextChanged 上的 PropertyChangedDataContext 等事件用於目標執行個體相關的自訂初始化。

大小和位置

當窗體顯示在彈出視窗中時,會根據窗體的 WidthHeightMinWidthMinHeight 屬性來決定其初始大小。 如果未為表單設定這些屬性,則會根據其內容來計算表單的初始大小。

我們建議您依照下文所述的方式設定這些內容:

  • 設定表單的 WidthHeight 等內容,以明確地指定適當大小。 請考慮將上述內容設定為 Auto 值。 如此能根據內容的大小設定表單的寬度和高度。

  • 設定表單的 MinWidthMinHeight 等內容,以指定可接收的最小表單視窗。 如果使用者將視窗大小調整為比指定值還小,畫面中會出現捲軸以供捲動至隱藏的表單內容。

當窗體裝載於 Service Manager 表單主機內時,會保留上次使用的大小和位置,以供相同使用者在同一個執行會話中後續顯示該表單。

重新整理

表單的目標執行個體可能會由於您針對表單執行 Refresh 命令而變更。 此命令的處理常式會從資料庫擷取新資料。 當數據送達時,表單的 DataContext 屬性值會設定為新的目標實例,並引發 DataContextChanged 事件。

若要區分首次載入表單時產生的 DataContextChanged 事件和為了處理 Refresh 命令而產生的事件,請查看隨事件傳入之事件引數的 OldValue 內容。 對於剛初始化的表單,此內容會是 Null。

提交變更

Service Manager 中的表單主機彈出視窗會提供按鈕來提交表單中所做的變更,以及關閉彈出視窗。

當使用者選取表單的 [ 套用 ] 按鈕時,會提交窗體的目標實例以供儲存。 這項作業是同步的;因此,在提交作業完成之前,用戶無法編輯表單。 如果在表單提交期間發生失敗,錯誤訊息會出現。 此時表單將維持開啟狀態,以便您做出進一步的變更。 我們建議使用者經常套用變更,以避免因其他使用者同時編輯表單的其他執行個體而發生衝突。

如果使用者選取 [ 確定 ] 按鈕,則行為類似於 [ 套用],不同之處在於,如果窗體提交作業成功,窗體及其主視窗就會關閉。

如果使用者選取 [ 取消 ] 按鈕,就會顯示一個對話框,要求使用者確認作業。 用戶可以選取 [是 ] 並遺失變更,或選取 [ ] 並返回窗體。

表單的一般指導方針和最佳做法

您可以藉由新增或修改表單來擴充 Service Manager 的功能。 本節說明建立和使用 Service Manager 窗體的一些最佳做法建議,以及直接使用各種工具和腳本窗體定義。

本節主要以使用 #D4A9D58D347864B9799C1D1AF0D144858 (WPF) 和 Microsoft Visual Studio Team System 或 Microsoft Expression Blend 來建置自己的自定義窗體的合作夥伴和客戶為目標。

撰寫新表單的一般指導方針如下:

  • 使用標準控制項。
  • 遵循一般表單設計指導方針。
  • 避免程式碼後置。
  • 包含例外狀況處理。
  • 考量表單自訂與升級。
  • 命名所有可自訂控制項。
  • 將表單繫結至資料來源。
  • 使用 Service Manager 表單基礎結構驗證規則、值轉換器和錯誤範本。
  • 使用表單基礎結構命令和事件。

如需這些指導方針的詳細資訊,請參閱下列各節。

使用標準控件

表單上使用的控制項可以是:

  • 標準控件。 這包括 .NET 程式庫控制項,例如下拉式方塊和清單方塊。
  • 自定義控制件。 這包括表單作者或協力廠商建立的其他控制項。

提示

在可能的情況下使用標準控制項並避免建立自訂控制項,即可提升與表單使用體驗相關的一致性。 如果您必須建立自訂控制項,請使用控制項範本定義控制項的外觀,將視覺外觀與行為以及邏輯行為分開。 最好是每個 Windows 佈景主題都有個別的控制項範本。

遵循一般表單設計指導方針

在設計表單時,請使用公開的設計指導方針,確保表單不僅方便使用,而且符合一般的使用者互動典範。

如需一般 Windows 設計的詳細資訊,請參閱 Windows User Experience Interaction Guidelines (Windows 使用者經驗指導方針)

此外:

  • 在多個實驗室之間分割資訊,讓表單變得更簡單也更方便閱讀。 在第一個索引標籤中包含最常用的資訊,以及後續索引標籤上較不重要的資訊。
  • 使用版面配置面板來編排表單上的控制項。 這可確保表單在重設大小和當地語系化時會正確運作。
  • 避免設定個別控制項視覺內容,並改用樣式。 這可讓您藉由修改樣式來變更一系列窗體上所有控件的外觀,並提升相關窗體的一致外觀。

避免程式代碼後置

程式碼後置 」一詞係用來描述對 XAML 頁面進行標記編譯時與標記定義之物件聯結的程式碼。 請盡可能避免在表單中使用程式碼後置。 最好是在控件本身內嵌表單的程式代碼,因為稍後變更該程式代碼會比較容易。 請改用 Service Manager 表單基礎結構支援的宣告式功能,在表單中定義值轉換和驗證規則。

一般指導方針是,您應該將程式代碼後置的使用限制為無法使用 XAML 的宣告式功能,以及 WPF 和表單基礎結構連結庫中定義的類別,來提供所需的功能。 即使如此,您仍應考慮將程式碼後置中實作的功能移入協助程式程式庫,然後從 XAML 參照該程式庫。

包含例外狀況處理

請確定表單中的程式代碼包含例外狀況處理,以便在撰寫工具的設計階段和運行時間於 Service Manager 控制台中載入表單。

考慮表單自定義和升級

當您設計新的表單時,應該考慮未來的自定義和升級至該表單。 若要確保可以自定義及升級窗體,同時保留自定義,請遵循本節先前提供的指導方針和秘訣,以及下列指導方針:

  • 設計表單時,請考慮日後自定義和升級。 表單可能會在未來的版本中演進,而且請務必考慮使用者如何升級至新版窗體,同時保留對原始窗體的自定義。 例如,在使用者已投入大量資源自訂原始表單之後,您可能會提供更新的表單。 使用者希望在版本升級後,仍可保留他們的自訂內容。

  • 為表單上的每個控制項提供唯一的名稱,讓您可將自訂套用到控制項。 表單自訂會儲存成以特定控制項或一組控制項作為目標的一組動作。 目標控件會依名稱參考,這就是為什麼必須跨表單版本保留控件名稱。 如果控件沒有名稱,表單自定義 編輯器 會產生名稱,但產生的名稱不會保留在表單的不同版本。

  • 請確定控制項名稱在表單的不同版本之間保持不可變。 這可確保先前版本中特定控制項的自訂可以套用到新版表單中的相同控制項。

  • 如果可能,在升級表單時,請避免將控制項移到相同索引標籤的不同位置。 常見的使用者自訂是在表單上將控制項移到不同的位置。 如果您在新版表單中變更控制項的位置,新控件位置可能會與使用者重新放置的控件重疊的風險。

  • 可能的話,當您設計現有表單的更新時,請避免在索引卷標之間移動控件。 控件會依名稱和索引標籤來識別它們。 在新版表單中將控制項從某個索引標籤移到另一個,可能會破壞使用者對該控制項進行的自訂,因為這些自訂將無法識別目標控制項。

  • 當表單的更新包含新的控制項時,請考慮將新的控件新增至新的索引標籤。這是避免干擾現有索引標籤和控制項之任何使用者自定義的最安全方式。

  • 請注意控制項的繫結方式。 唯讀控制項只能使用單向繫結。

將所有可自定義的控制件命名

請確認控制項名稱係描述控制項所繫結的資料,或是描述控制項的功能。

將窗體系結至數據源

表單 Service Manager一物件。 這個物件稱為 target instance,且一律由表單的 DataContext 內容 (繼承自 FrameworkElement 類別) 指定。

重要

請勿修改表單的 DataContext 屬性。 表單裝載環境使用這個內容來識別表單目標執行個體。

在 Service Manager 數據模型中,目標實例會以 BindableDataItem 物件表示。 這個類別可彙總軟體開發套件 (SDK) 物件,並透過採用內容名稱作為參數的索引子公開其內容。

BindableDataItem 類別也會實作 ICustomTypeDescriptor,使您能夠使用 BindableDataItem 類別作為 WPF 繫結的資料來源。 下列範例顯示將目標執行個體內容繫結至 Text 控制項的 TextBox 內容:


<TextBox Name="textBoxDescription" Text="{Binding Path=Summary}"/>

不需要指定系 結的來源, 因為目標實例會設定為窗體的 DataContext ,這會做為窗體上所有控件的預設 Source

表單上的控制項可以系結至目標實例以外的數據源,而表單基礎結構連結庫包含許多以隱含方式執行系結的控制項。 例如,執行個體選擇器控制項會繫結到資料來源,由資料來源提供可供選擇的執行個體集合。 您也可以使用 ObjectDataProviderXmlDataProvider 類別,以宣告方式定義其他數據源。

表單基礎結構會將目標執行個體視為表單上的唯一讀/寫資料來源。 因此, Submit 命令的實作只會儲存對目標執行個體所做的變更。 表單的其他資料來源都被視為唯讀。

使用 Service Manager 表單基礎結構驗證規則、值轉換器和錯誤範本

建議您在表單中使用表單基礎結構驗證規則來指定無效的數據輸入。 WPF 繫結基礎結構可支援驗證以單向或雙向繫結繫結至資料來源的控制項內容。 繫結物件具有 ValidationRules 集合,而此集合可以包含任何數目的 ValidationRule 物件。 每當資料從控制項推播到資料來源時,系統都會呼叫 ValidationRule 物件來驗證值。

表單基礎結構連結庫包含許多可處理最常見案例的驗證規則。 表單基礎結構利用這些驗證規則來判斷表單內容是否可提交以供儲存。 例如,如果表單上有驗證錯誤的控件,則可以停用表單的 [ 提交 ] 按鈕。

建議您使用表單基礎結構程式庫所提供的自訂錯誤範本。 如果控制項發生驗證錯誤,依預設其周圍會出現紅色框線。 WPF 可讓您透過 Validation.ErrorTemplate 內容 (可在任何控制項上設定) 定義自訂錯誤指標。 Service Manager 表單基礎結構連結庫包含自定義錯誤範本,其會顯示錯誤圖示,而不是 WPF 紅色框線。 此外,當滑鼠指向錯誤圖示時,將會出現內含錯誤訊息的工具提示。 錯誤訊息應該會指出控制項中資料驗證失敗的原因。

下列範例顯示如何在 XAML 中參照此錯誤範本:


<TextBox Text="{Binding SomeProperty}"
         scwpf:Validation.ValueRequired="True"
         Validation.ErrorTemplate="{DynamicResource {ComponentResourceKey {x:Type scwpf:Validation}, InvalidDataErrorTemplate}}"/>

如果內建驗證規則未提供必要的驗證邏輯,建議您建置自定義驗證規則來代表該邏輯。 如此便可讓標準和自訂驗證邏輯共存在一般驗證處理機制內。

如果驗證規則機制不適用於特定案例,您應該改為處理 FormEvents.PreviewSubmitEvent ,並從該處執行驗證。

下列程式碼範例提供可用來執行自訂驗證的模式範例:


void MyForm_Loaded(object sender, RoutedEventArgs e)
{
    // hook to handle form events
    this.AddHandler(
        FormEvents.PreviewSubmitEvent,
        new EventHandler<PreviewFormCommandEventArgs>(this.OnPreviewSubmit));
}
private void OnPreviewSubmit(object sender, PreviewFormCommandEventArgs e)
{
    string errorMessage;
    bool result = this.DoVerify(out errorMessage);
    if (!result)
    {
        // cancel Submit operation
        e.Cancel = true;
        // display error message
        MessageBox.Show(errorMessage);
    }
}
internal bool DoVerify(out string errorMessage)
{
    // Do custom verification and return true to indicate that
    // validation check has passed; otherwise return false and
    // populate errorMessage argument
}

使用表單基礎結構命令和事件

表單基礎結構會公開許多可在窗體上執行的命令。 這些命令包括:

  • FormsCommand.Submit,用於儲存表單的目標執行個體。

  • FormsCommand.SubmitAndClose,用於儲存表單的目標執行個體並關閉表單。

  • FormsCommand.Refresh,用於重複查詢表單的目標執行個體。

  • FormCommands.Cancel,會捨棄所有變更並關閉表單。

這些命令前後都以事件包圍,在命令執行之前和之後都會產生事件。

執行命令之前會產生下列事件:

  • FormEvents.PreviewSubmit 事件在 FormCommand.Submit 命令之前產生,而 FormEvents.Submitted 事件則在 FormCommand.Submit 命令之後產生。

  • FormEvents.PreviewRefresh 事件在 FormCommands.Refresh 命令之前產生,而 FormCommand.Refreshed 命令則在 FormCommand.Submit 命令之後產生。

  • FormEvents.PreviewCancel 事件在 FormCommands.Cancel 命令之前產生,而 FormCommand.Canceled 事件則在 FormCommand.Cancel 命令之後產生。

預覽事件可傳遞 PreviewFormCommandEventArgs 物件。 這個物件包含可變動的 Cancel 內容,當此內容設定為 true時,即可讓對應的命令無法執行。

命令後續事件可傳遞 FormCommandExecutedEventArgs 物件。 此物件包含 Result 內容,指出命令是否執行成功、已取消或造成錯誤。 若發生錯誤, FormCommandExecutedEventArgs 物件的 Error 內容便會參照例外狀況,提供錯誤相關資訊。

可以透過程序設計方式和宣告方式啟用、停用及執行表單命令。

若要以程式啟用表單命令,請在表單和相關命令之間建立 CommandBinding

下列範例在表單和 Refresh 命令之間建立了命令繫結,並針對此命令定義了兩個處理常式。 第一個處理常式傳回 Refresh 命令是否可執行,而第二個處理常式實際包含了 Refresh 命令的實作:


    public class MyForm : UserControl
    {
        public MyForm()
        {
            // do standard initialization
            // establish CommandBinding for Refresh command
            this.CommandBindings.Add(
                new CommandBinding(FormCommands.Refresh, this.ExecuteRefresh, this.CanExecuteRefresh));
        }
        private void CanExecuteRefresh(
              object sender,
              CanExecuteRoutedEventArgs e)
        {
            // put your logic that determines whether Refresh
// can be executed here
            bool canExecute = true;
            BindableDataItem dataItem = this.DataContext as BindableDataItem;
            if (dataItem)
            {
                canExecute = dataItem["Status"] != "New";
            }
            e.CanExecute = canExecute;
        }
        private void ExecuteRefresh(
            object sender,
            ExecutedRoutedEventArgs e)
        {
            // here is placeholder for the code that has do be
// executed upon running Refresh command
        }
    }

您也可以宣告方式定義表單的處理常式。 您可以採用使用 RoutedCommandTriggerRule物件來執行此作業。 下列程式碼範例顯示如何以宣告方式定義處理常式:


    <scwpf:BusinessLogic.Rules>
        <scwpf:RuleCollection>
            <scwpf:Rule>
                <scwpf:Rule.Triggers>
                    <scwpf:RoutedCommandTrigger
RoutedCommand="{x:Static scwpf:FormCommands.Refresh}"/>
                </scwpf:Rule.Triggers>
                <scwpf:Rule.Conditions>
                    <scwpf:PropertyMatchCondition
                        Binding="{Binding Status}"
                        Value="New"
                        Operation="NotEquals" />
                </scwpf:Rule.Conditions>
                <!-- Use RuleAction objects to define the logic that executed
                upon running Refresh command; this can be left empty -->
            </scwpf:Rule>
        </scwpf:RuleCollection>
    </scwpf:BusinessLogic.Rules>

下一步