將使用者介面自動化功能新增至活動輔助功能伺服器
如果控件沒有 Microsoft 使用者介面自動化提供者,但已實作 IAccessible,則可以藉由實作 IAccessibleEx 介面來輕鬆升級,從而提供一些使用者介面自動化功能。 這個介面可讓控件公開 使用者介面自動化 屬性和控件模式,而不需要完整實作 使用者介面自動化 提供者介面,例如 IRawElementProviderFragment。 若要實作 IAccessibleEx,基準Microsoft Active Accessibility 物件階層不得包含任何錯誤或不一致(例如父物件未將它列為子系的子物件),且不得與 使用者介面自動化 規格衝突。 如果 Microsoft Active Accessibility 物件階層符合這些要求,那麼使用IAccessibleEx;來新增功能會是理想的選擇。否則,您需要單獨實作 UI 自動化或將其與 Microsoft Active Accessibility 的實作結合使用。
以具有範圍值的自訂控制為例。 控件的 Microsoft Active Accessibility 伺服器會定義其角色,而且能夠傳回其目前值,但缺少傳回控件最小值和最大值的方法,因為這些屬性未定義於 Microsoft Active Accessibility 中。 使用者介面自動化 客戶端能夠擷取控件的角色、目前值和其他Microsoft Active Accessibility 屬性,因為 使用者介面自動化 核心可以透過 IAccessible 取得這些屬性。 不過,若無法存取 物件上的IRangeValueProvider 介面,使用者介面自動化 也無法擷取最大值和最小值。
控件開發人員可以為控件提供完整的UI自動化提供者,但這意味著複製IAccessible實作的大部分現有功能,例如導覽和常用屬性。 相反地,開發人員可以繼續依賴 IAccessible 提供這項功能,同時透過 IRangeValueProvider 新增控件特定屬性的支援。
更新自訂控制項需要下列主要步驟:
- 在可存取物件上實作IServiceProvider,以便在此物件或其他物件上找到 IAccessibleEx 介面。
- 在可存取的對象上實作 IAccessibleEx。
- 為任何 Microsoft Active Accessibility 子項目建立個別的可存取物件,其中在 Microsoft Active Accessibility 中,可能是由父物件上的 IAccessible 介面表示(例如,列表項目)。 在這些對象上實作IAccessibleEx。
- 在所有可存取的對象上實作 IRawElementProviderSimple。
- 在可存取的對象上實作適當的控制項模式介面。
本主題包含下列各節。
公開 IAccessibleEx
由於控件的 IAccessibleEx 實作可能位於不同的 物件中,用戶端應用程式無法依賴 QueryInterface 來取得這個介面。 相反地,客戶端應該呼叫 IServiceProvider::QueryService。 在下列這個方法的範例實作中,假設 IAccessibleEx 未實作於個別物件上,因此方法只會呼叫 QueryInterface。
HRESULT CListboxAccessibleObject::QueryService(REFGUID guidService, REFIID riid, LPVOID *ppvObject)
{
if (!ppvObject)
{
return E_INVALIDARG;
}
*ppvObject = NULL;
if (guidService == __uuidof(IAccessibleEx))
{
return QueryInterface(riid, ppvObject);
}
else
{
return E_INVALIDARG;
}
};
實作 IAccessibleEx
在 IAccessibleEx 接口中最感興趣的方法是 GetObjectForChild。 這個方法可讓 Microsoft Active Accessibility 伺服器有機會為子項目建立可存取的物件(至少 實現 IAccessibleEx)。 在 Microsoft Active Accessibility 中,子項目通常不會表示為可存取的物件,而是視為可存取物件的子項目。 不過,由於 使用者介面自動化 要求每個元素都以個別的可存取物件表示,GetObjectForChild 必須依需求為每個子系建立個別的物件。
下列範例實作會傳回一個可存取的物件,用於自訂清單檢視中的專案。
HRESULT CListboxAccessibleObject::GetObjectForChild(long idChild, IAccessibleEx **pRetVal)
{
*pRetVal = NULL;
VARIANT vChild;
vChild.vt = VT_I4;
vChild.lVal = idChild;
// ValidateChildId is an application-defined function that checks whether
// the child ID is valid. This is similar to code that validates the varChild
// parameter in IAccessible methods.
//
// Additionally, if this idChild corresponds to a child that has its own
// IAccessible, we should also return E_INVALIDARG here. (The caller
// should instead be using the IAccessibleEx from that child's own
// IAccessible in that case.)
if (idChild == CHILDID_SELF || FAILED(ValidateChildId(vChild)))
{
return E_INVALIDARG;
}
// Return a suitable provider for this specific child.
// This implementation returns a new instance each time; an implementation
// can cache these if desired.
// _pListboxControl is a member variable pointer to the owning control.
IAccessibleEx* pAccEx = new CListItemAccessibleObject(idChild, _pListboxControl);
if (pAccEx == NULL)
{
return E_OUTOFMEMORY;
}
*pRetVal = pAccEx;
return S_OK;
}
如需完整的範例實作,請參閱讓自定義控件可供存取,第 5 部分:使用 IAccessibleEx 將 使用者介面自動化 支援新增至自定義控件。
相關主題