屬性表和屬性頁
對象的屬性會透過 COM 介面或物件的 IDispatch 實作,向客戶端公開與方法相同,讓呼叫這些方法的程式可以變更屬性。 屬性頁的 OLE 技術提供根據 Windows 使用者介面標準為物件屬性建置使用者介面的方法。 因此,屬性會公開給終端使用者。 對象的屬性表是Tabbed-dialog,其中每個索引標籤對應至特定屬性頁。 使用屬性頁的 OLE 模型包含下列功能:
- 每個屬性頁都是由實作 IPropertyPage 或 IPropertyPage2 的進程中物件所管理。 每個頁面都會以自己的唯一 CLSID 來識別。
- 物件會藉由實 作 ISpecifyPropertyPages 來指定對屬性頁的支援。 透過這個介面,呼叫端可以取得CLSID清單,以識別物件支援的特定屬性頁。 如果物件指定屬性頁 CLSID,對象必須能夠從屬性頁接收屬性變更。
- 任何想要顯示物件屬性表的程式代碼片段都會傳遞物件的IUnknown 指標(如果多個物件受到影響,則為陣列),並將頁面 CLSID 數位列傳送至 OleCreatePropertyFrame 或 OleCreatePropertyFrameIndirect,以建立 tabbed-dialog 方塊。
- 屬性框架對話框會在每個 CLSID 上使用 CoCreateInstance ,具現化每個屬性頁的單一實例。 屬性框架至少會取得每個頁面的 IPropertyPage 指標。 此外,框架會針對每個頁面自行建立屬性頁網站物件。 每個網站都會實作 IPropertyPageSite ,並將此指標傳遞至每個頁面。 然後頁面會透過這個介面指標與網站通訊。
- 每個頁面也會知道已叫用該頁面的物件或物件;也就是說,屬性框架會將物件的IUnknown指標傳遞給每個頁面。 當指示將變更套用至物件時,每個頁面都會查詢適當的介面指標,並以任何需要的方式將新的屬性值傳遞給物件。 沒有關於這種溝通如何發生的規定。
- 物件也可以支援每個屬性流覽 IPerPropertyBrowsing 介面,允許物件指定屬性在屬性頁顯示時應接收初始焦點的屬性,以及指定用戶端在其使用者介面中可以顯示的字串和值。
下圖說明這些功能:
這些介面的定義如下:
interface ISpecifyPropertyPages : IUnknown
{
HRESULT GetPages([out] CAUUID *pPages);
};
interface IPropertyPage : IUnknown
{
HRESULT SetPageSite([in] IPropertyPageSite *pPageSite);
HRESULT Activate([in] HWND hWndParent, [in] LPCRECT prc
, [in] BOOL bModal);
HRESULT Deactivate(void);
HRESULT GetPageInfo([out] PROPPAGEINFO *pPageInfo);
HRESULT SetObjects([in] ULONG cObjects
, [in, max_is(cObjects)] IUnknown **ppunk);
HRESULT Show([in] UINT nCmdShow);
HRESULT Move([in] LPCRECT prc);
HRESULT IsPageDirty(void);
HRESULT Apply(void);
HRESULT Help([in] LPCOLESTR pszHelpDir);
HRESULT TranslateAccelerator([in] LPMSG pMsg);
}
interface IPropertyPageSite : IUnknown
{
HRESULT OnStatusChange([in] DWORD dwFlags);
HRESULT GetLocaleID([out] LCID *pLocaleID);
HRESULT GetPageContainer([out] IUnknown **ppUnk);
HRESULT TranslateAccelerator([in] LPMSG pMsg);
}
ISpecifyPropertyPages::GetPages 方法會傳回 UUID (GUID) 值的計數數位,每個值都會描述物件想要顯示之屬性頁的 CLSID。 神秘 ever 使用 叫用屬性表OleCreatePropertyFrame 或 OleCreatePropertyFrameIndirect 會將這個數位傳遞至函式。 請注意,如果呼叫端想要顯示多個物件的屬性頁,它只能將所有物件的 CLSID 清單交集傳遞給這些函式。 換句話說,呼叫端只能叫用所有物件通用的屬性頁。
此外,呼叫端也會將 IUnknown 指標傳遞給受影響的物件至 API 函式。 這兩個 API 函式都會建立屬性框架對話框,併為其載入的每個頁面具現化具有 IPropertyPageSite 的頁面網站。 透過這個介面,屬性頁可以:
- 透過 GetLocaleID 擷取屬性表中所使用的目前語言。
- 要求畫面透過 TranslateAccelerator 處理按鍵。
- 透過 OnStatusChange 通知頁面上的變更框架。
- 透過 GetPageContainer 取得框架本身的介面指標,不過此函式目前沒有為框架定義的介面一律會傳回E_NOTIMPL。
屬性框架會具現化每個屬性頁物件,並取得每個頁面的 IPropertyPage 介面。 透過這個介面,框架會通知其頁面網站的頁面 (SetPageSite),擷取頁面維度和字串串 (GetPageInfo),將介面指標傳遞給受影響的物件 (SetObjects),告知頁面何時建立和終結其控件 (Activate and Deactivate),指示頁面顯示或重新定位本身 (顯示和移動)會指示頁面將目前的值套用至受影響的物件(Apply)、檢查頁面的骯髒狀態(IsPageDirty)、叫用說明(說明),並將擊鍵傳遞至頁面(TranslateAccelerator)。
物件也可以支援個別屬性流覽,其提供:
- 一種方式(透過 IPerPropertyBrowsing 和 IPropertyPage2)指定當屬性表第一次顯示屬性表時,應該在哪個屬性頁面上指定初始焦點
- 物件的方法(透過 IPerPropertyBrowsing)指定預先定義的值和對應的描述性字串,這些字串可以在用戶端自己的使用者介面中顯示屬性。
物件可以選擇支援 (2) 而不支援 (1),例如當物件沒有屬性表時。
IPropertyPage2 和 IPerPropertyBrowsing 介面的定義如下:
interface IPerPropertyBrowsing : IUnknown
{
HRESULT GetDisplayString([in] DISPID dispID, [out] BSTR *pbstr);
HRESULT MapPropertyToPage([in] DISPID dispID, [out] CLSID *pclsid);
HRESULT GetPredefinedStrings([in] DISPID dispID, [out] CALPOLESTR *pcaStringsOut, [out] CADWORD *pcaCookiesOut);
HRESULT GetPredefinedValue([in] DISPID dispID, [in] DWORD dwCookie, [out] VARIANT *pvarOut);
}
interface IPropertyPage2 : IPropertyPage
{
HRESULT EditProperty([in] DISPID dispID);
}
若要指定對這類功能的支援,物件會實作 IPerPropertyBrowsing。 透過這個介面,呼叫端可以要求完成流覽所需的資訊,例如預先定義的字串 (GetPredefinedStrings) 和值 (GetPredefinedValue) 以及指定屬性的顯示字元串 (GetDisplayString)。
此外,用戶端可以取得屬性頁的 CLSID,讓使用者編輯以 DISPID (MapPropertyToPage) 識別的指定屬性。 然後,用戶端會指示屬性框架一開始啟動該頁面,方法是將CLSID和DISPID傳遞至OleCreatePropertyFrameIndirect。 框架會先啟動該頁面,並透過 IPropertyPage2::EditProperty 將 DISPID 傳遞至頁面。 然後頁面會將焦點設定為該屬性的編輯欄位。 如此一來,用戶端就可以從本身使用者介面中的屬性名稱跳至可以操作該屬性的屬性頁面。
相關主題