伺服器端 UI 自動化供應者實作

備註

本文件適用對象為 .NET Framework 開發人員,其想要使用 System.Windows.Automation 命名空間中定義的受控 UI 自動化類別。 欲了解最新的 UI 自動化資訊,請參閱 Windows 自動化 API:UI 自動化。

本節說明如何實作伺服器端 UI 自動化提供者以支援自訂控制項。

Windows Presentation Foundation(WPF)元素與非 WPF 元素(例如為 Windows Forms 設計的元素)的實作本質上不同。 WPF 元素透過衍生的 AutomationPeer類別支援 UI 自動化。 非 WPF 元素透過提供者介面的實作提供支援。

安全性考慮

提供者應該被寫成能在部分信任環境中運作。 因為 UIAutomationClient.dll 沒有設定以在部分信任下執行,因此您的提供者程式碼不應參考該程式集。 若如此,程式碼可能在全信任環境中執行,但在部分信任環境中失敗。

特別地,不要使用 UIAutomationClient.dll 類別中的欄位,例如在 AutomationElement 中的欄位。 相反地,使用 UIAutomationTypes.dll類別中的等價欄位,例如 AutomationElementIdentifiers。

Windows Presentation Foundation Elements 的提供者實作

欲了解更多相關資訊,請參閱 WPF 自訂控制項的 UI 自動化。

適用於非 WPF 元素的提供者實作

非 WPF 框架一部分、但以受管程式碼撰寫的自訂控制項(多為 Windows 表單控制項)透過實作介面來支援 UI 自動化。 每個元素必須至少實作下一節第一個表格中列出的介面之一。 此外,若元素支援一個或多個控制模式,必須為每個控制模式實作適當的介面。

您的 UI 自動化提供者專案必須參考以下組件:

  • UIAutomationProviders.dll

  • UIAutomationTypes.dll

  • WindowsBase.dll

提供者介面

每個 UI 自動化提供者都必須實作以下其中一個介面。

介面 說明
IRawElementProviderSimple 提供可在視窗中承載的簡單控制的功能,包括控制模式與屬性支援。
IRawElementProviderFragment 繼承自 IRawElementProviderSimple。 新增複雜控制元素的功能,包括片段內的導航、設定焦點及回傳元素的邊界矩形。
IRawElementProviderFragmentRoot 繼承自 IRawElementProviderFragment。 新增複雜控制項根元素的功能,包括在指定座標定位子元素及設定整個控制項的焦點狀態。

以下介面提供額外功能,但並非必須實作。

介面 說明
IRawElementProviderAdviseEvents 使提供者能追蹤活動請求。
IRawElementProviderHwndOverride 允許在片段的 UI 自動化樹中重新定位基於視窗的元素。

命名空間中 System.Windows.Automation.Provider 的所有其他介面都是用於控制模式支援。

非 WPF 供應商的需求

為了與 UI 自動化溝通,您的控制必須實作以下主要功能領域:

功能性 實施
讓提供者接受 UI 自動化 對於發送到控制視窗的 WM_GETOBJECT 訊息,回傳實作 IRawElementProviderSimple 的物件(或衍生介面)。 對於片段,這必須是片段根的提供者。
提供房產價值 實作 GetPropertyValue 以提供或覆蓋數值。
讓客戶端能夠與控制項互動 實作支援控制模式的介面,例如 IInvokeProvider。 在你的GetPatternProvider實作中,回傳這些模式提供者。
引發事件 呼叫其中一個靜態方法 AutomationInteropProvider 來觸發一個讓客戶端能監聽的事件。
在片段內啟用導航與聚焦功能 針對片段中的每個元素實作 IRawElementProviderFragment 。 (對於非片段中的元素則不必要。)
啟用子元素在片段中的聚焦與定位 實作 IRawElementProviderFragmentRoot。 (對於非片段根的元素則不需如此。)

非WPF提供者的財產價值

用於自訂控制項的 UI 自動化服務提供者必須支援某些屬性,以便自動化系統和用戶端應用程式都能加以使用。 對於託管在視窗中的元素(HWND),UI 自動化可以從預設視窗提供者取得部分屬性,但必須從自訂提供者取得其他屬性。

基於 HWND 的控制提供者通常不需要提供以下屬性(以欄位值識別):

備註

在視窗中託管的簡單元素或片段根節點的資訊 RuntimeIdProperty 會從視窗中取得;然而,根節點下方的片段元素(例如清單框中的清單項目)必須提供自己的識別碼。 如需詳細資訊,請參閱GetRuntimeId。

應將 IsKeyboardFocusableProperty 回傳給托管在 Windows 表單控制項中的供應商。 在這種情況下,預設視窗提供者可能無法取得正確的值。

這 NameProperty 通常是由主機供應商提供。 例如,若自訂控制源自 Control,名稱即源自 Text 控制項的屬性。

例如程式碼範例,請參見 UI 自動化提供者的回傳屬性。

非WPF提供者的活動

UI 自動化提供者應觸發事件,通知客戶端應用程式 UI 狀態變更。 以下方法用於引發事件。

方法 說明
RaiseAutomationEvent 引發各種事件,包括由控制模式觸發的事件。
RaiseAutomationPropertyChangedEvent 當 UI 自動化屬性變更時,會觸發事件。
RaiseStructureChangedEvent 當 UI 自動化樹結構變更時,會觸發事件;例如,透過移除或添加元素。

事件的目的是通知用戶端使用者介面(UI)中發生的某些事,無論該活動是否是由 UI 自動化系統本身觸發。 例如,當控制項被呼叫時,應觸發由 識別的 InvokedEvent 事件,無論是透過使用者直接輸入或由客戶端應用程式呼叫 Invoke。

為了優化效能,提供者可以選擇性地提出事件,或若沒有客戶端應用程式註冊接收事件,則完全不觸發事件。 以下方法用於優化。

方法 說明
ClientsAreListening 此靜態屬性用以指定是否有用戶端應用程式訂閱了 UI 自動化事件。
IRawElementProviderAdviseEvents 提供者在片段根節點上實作此介面,使客戶端在片段事件註冊與取消註冊事件處理程序時,能獲得通知。

非 WPF 供應商導航

提供簡單控制項的提供者,例如在視窗中託管的自訂按鈕(HWND),則不需要在 UI 自動化樹中支援導覽。 到及離開元素的導覽由主視窗的預設提供者處理,該提供者在 HostRawElementProvider 的實作中有所規定。 然而,當你實作複雜自訂控制的提供者時,必須支援片段根節點與其後代節點之間的導航,以及兄弟節點之間的導航。

備註

片段中除根節點外的其他元素必須從HostRawElementProvider回傳null參考,因為它們並非直接託管在視窗中,且沒有任何預設提供者能支援往返它們的導航。

片段的結構取決於你對 的 Navigate實作。 對於每個片段的每個可能方向,此方法會回傳該方向元素的提供者物件。 如果該方向沒有元素,方法會回傳一個 null 參考。

片段根節點僅支援子元素的導覽。 例如,當方向為 FirstChild時,列表框回傳列表中的第一個項目,當方向為 LastChild時返回最後一個項目。 片段根不支援導航至父節點或同層節點;這由主機視窗控制器負責處理。

片段中非根節點的元素必須具有支援導航至其父節點、兄弟姊妹節點及子節點的能力。

非 WPF 提供者重新設定父層

彈出視窗其實是頂層視窗,因此預設會作為桌面的子視窗出現在 UI 自動化樹中。 然而,在許多情況下,彈出視窗在邏輯上是其他控件的子項。 例如,組合框的下拉選單在邏輯上是組合框的子項。 同樣地,選單彈出視窗在邏輯上是選單的子選單。 UI 自動化提供重新設定彈出視窗父子關係的支援,使其成為相關控制項的子視窗。

要重新保護彈出視窗:

  1. 為彈出視窗建立一個提供者。 這需要事先知道彈出視窗的類別。

  2. 像往常一樣實作該彈出視窗的所有屬性和模式,就像它本身就是一個控制項一樣。

  3. 實作該 HostRawElementProvider 特性,使其回傳從 HostProviderFromHandle取得的值,其中參數為彈出視窗的視窗柄。

  4. 實施Navigate 用於彈出視窗及其父視窗,確保從邏輯父節點到邏輯子視窗的導航,以及在兄弟節點之間的導航能正確處理。

當 UI 自動化遇到彈出視窗時,它會辨識到導航被預設視窗覆蓋,當彈出視窗作為桌面子視窗時,會跳過該視窗。 相反地,節點只能透過片段來存取。

重父處理不適用於控制項可承載任意類別視窗的情況。 例如,鋼筋可以在其帶內承載任何類型的 HWND。 為了處理這些情況,UI 自動化支援另一種 HWND 重新定位,詳見下一節所述。

非 WPF 提供者重新定位

UI 自動化片段可能包含兩個或多個元素,每個元素都包含在一個視窗(HWND)中。 由於每個 HWND 都有其預設提供者,該提供者將該 HWND 視為包含 HWND 的子節點,因此 UI 自動化樹預設會將片段中的 HWND 顯示為父視窗的子節點。 在大多數情況下,這是理想的行為,但有時會造成混淆,因為這與使用者介面的邏輯結構不符。

這方面的一個好例子是鋼筋控制過程。 鋼筋包含多個條帶,每個條帶又可能包含基於 HWND 的控制項,例如工具列、編輯框或組合框。 重疊列 HWND 的預設視窗提供者將工具帶控制 HWND 視為子節點,而重疊列提供者則將這些工具帶視為子節點。 由於 HWND 提供者與重排列提供者協同工作並合併其子項,因此群組和基於 HWND 的控制項都顯示為重排列的子項。 然而,從邏輯上來說,只有波段應該作為鋼筋的子節點出現,且每個波段提供者應與其所包含控制的預設 HWND 提供者相連。

為達成此目標,鋼筋的片段根提供者會暴露一組代表帶狀的子節點。 每個頻段都有單一提供者,可能會揭露屬性和模式。 在其實作 HostRawElementProvider 中,頻帶提供者回傳控制 HWND 的預設視窗提供者,該提供者是經由呼叫 HostProviderFromHandle 並傳遞控制的視窗代柄來取得的。 最後,鋼筋的片段根提供者實作了 IRawElementProviderHwndOverride 介面,並在其 GetOverrideProviderForHwnd 實作中回傳指定 HWND 控制項的合適頻段提供者。

另請參閱