Exemplo: implementando uma página de propriedades
Este exemplo mostra como criar uma página de propriedades que exibe (e permite que você altere) propriedades de interface de Classes de documento .Essa interface é exposto por documentos em Exemplos de modelo de objeto de ambiente comuns Visual Studio (embora a página de propriedades que você criará se não irá importar de onde ele manipulam objetos provenientes como suportam a interface correta).
o exemplo é baseado em exemplo de ATLPages.
Para concluir este exemplo, você:
Adicionar a classe da página de propriedades de ATL usando a caixa de diálogo da classe e adicionar o assistente da página de propriedades de ATL.
Edite o recurso da caixa de diálogo adicionando novos controles para as propriedades interessantes de interface de Documento .
adicionar manipuladores de mensagem para manter o site da página de propriedades informada das alterações feitas pelo usuário.
Adicione algumas declarações de #import e um typedef na seção de tarefas domésticas .
Substitua IPropertyPageImpl::SetObjects para validar os objetos que estão sendo passados para a página de propriedades.
substituição IPropertyPageImpl::Activate para inicializar a interface da página de propriedades.
substituição IPropertyPageImpl::Apply para atualizar o objeto com os valores de propriedade os últimos.
exibir a página de propriedades criando um objeto auxiliar simples.
Crie uma macro que irá testar a página de propriedades.
Adicionando a classe da página de propriedades de ATL
Primeiro, crie um novo projeto de ATL para um servidor de DLL chamado ATLPages7.Use agora Assistente da página de propriedades de ATL para gerar uma página de propriedades.Execute a página de propriedades de Nome curto de DocProperties então alterne para a página de Cadeias de caracteres aos itens propriedade-página- específicos definidos como mostrado na tabela abaixo.
Item |
Valor |
---|---|
Nome |
TextDocument |
Cadeia de caracteres de Doc |
Propriedades de VCUE TextDocument |
Helpfile |
<blank> |
Os valores que você configurou em esta página do assistente será retornado para o contêiner da página de propriedades quando chamar IPropertyPage::GetPageInfo.O que acontece a cadeias de caracteres em seguida que é dependente no contêiner, mas será normalmente usado para identificar sua página para o usuário.O título aparecerá geralmente em uma guia acima da página e a cadeia de caracteres de Doc pode ser exibida em uma barra de status ou em uma dica de ferramenta (embora o quadro de propriedade padrão não usa essa cadeia de caracteres de qualquer).
Observação |
---|
As cadeias de caracteres que você definir aqui é armazenado como recursos de cadeia de caracteres em seu projeto pelo assistente.Você pode facilmente editar estas cadeias de caracteres usando o editor de recursos se você precisar alterar essa informação após o código para a página foi gerado. |
Clique OK para que o assistente gere sua página de propriedades.
Editando o recurso da caixa de diálogo
Agora que a página de propriedades foi gerada, você precisará adicionar alguns controles ao recurso da caixa de diálogo que representa sua página.Adicione uma caixa de edição, um controle de texto estático, e uma caixa de seleção e defina seus IDs como mostrado abaixo:
Esses controles serão usados para exibir o nome de arquivo do documento e de seu status somente leitura.
Observação |
---|
O recurso da caixa de diálogo não inclui um quadro ou botões de comando, ou terá o aspecto com guias que você pode ter esperado.Esses recursos são fornecidos por um quadro da página de propriedades como o criado chamando OleCreatePropertyFrame. |
Adicionando manipuladores de mensagem
Com os controles no lugar, você pode adicionar manipuladores de mensagem para atualizar o status sujo de página quando o valor de qualquer uma das alterações de controles:
BEGIN_MSG_MAP(CDocProperties)
COMMAND_HANDLER(IDC_NAME, EN_CHANGE, OnUIChange)
COMMAND_HANDLER(IDC_READONLY, BN_CLICKED, OnUIChange)
CHAIN_MSG_MAP(IPropertyPageImpl<CDocProperties>)
END_MSG_MAP()
// Respond to changes in the UI to update the dirty status of the page
LRESULT OnUIChange(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
wNotifyCode; wID; hWndCtl; bHandled;
SetDirty(true);
return 0;
}
Esse código responde às alterações feitas ao controle ou para a caixa de seleção de edição chamando IPropertyPageImpl::SetDirty, que informa ao site da página que a página foi alterado.Normalmente o site da página irá responder ativar ou desativar um botão de Aplicar do elemento da página de propriedades.
Observação |
---|
Em suas próprias páginas de propriedades, você pode precisar manter controle com precisão que as propriedades foram alteradas pelo usuário para que você possa atualizar evitar as propriedades que não foram alteradas.Implementa este exemplo de código que se para manter controle dos valores originais de propriedade e comparando com os valores atuais da interface do usuário quando é hora de aplicar as alterações. |
Tarefas domésticas
Agora adicione um par instruções de #import a DocProperties.h de modo que o compilador saber sobre a interface de Documento :
// MSO.dll
#import <libid:2DF8D04C-5BFA-101B-BDE5-00AA0044DE52> version("2.2") \
rename("RGB", "Rgb") \
rename("DocumentProperties", "documentproperties") \
rename("ReplaceText", "replaceText") \
rename("FindText", "findText") \
rename("GetObject", "getObject") \
raw_interfaces_only
// dte.olb
#import <libid:80CC9F66-E7D8-4DDD-85B6-D9E6CD0E93E2> \
inject_statement("using namespace Office;") \
rename("ReplaceText", "replaceText") \
rename("FindText", "findText") \
rename("GetObject", "getObject") \
rename("SearchPath", "searchPath") \
raw_interfaces_only
Você também precisará fazer referência à classe base de IPropertyPageImpl ; adicione o seguinte typedef a classe de CDocProperties :
typedef IPropertyPageImpl<CDocProperties> PPGBaseClass;
Substituindo IPropertyPageImpl::SetObjects
O primeiro método de IPropertyPageImpl que você precisa substituir é SetObjects.Aqui você adicionará código para verificar de apenas um único objeto é passado e que oferece suporte à interface de Documento que você está aguardando:
STDMETHOD(SetObjects)(ULONG nObjects, IUnknown** ppUnk)
{
HRESULT hr = E_INVALIDARG;
if (nObjects == 1)
{
CComQIPtr<EnvDTE::Document> pDoc(ppUnk[0]);
if (pDoc)
hr = PPGBaseClass::SetObjects(nObjects, ppUnk);
}
return hr;
}
Observação |
---|
Faz sentido suporte somente um único objeto para essa página porque você permitirá que o usuário definia o nome de arquivo do objeto somente um arquivo pode existir em qualquer um local. |
Substituindo IPropertyPageImpl::Activate
A próxima etapa é inicializar a página de propriedades com valores de propriedade do objeto subjacente quando a página é criada primeiramente.
Em esse caso você deve adicionar os seguintes membros para a classe como você também irá usar os valores de propriedades iniciais para comparação quando os usuários da página aplicam as alterações:
CComBSTR m_bstrFullName; // The original name
VARIANT_BOOL m_bReadOnly; // The original read-only state
A implementação da classe base do método de Ativar é responsável para criar a caixa de diálogo e seus controles, então você pode substituir esse método e adicionar sua própria inicialização após chamar a classe base:
STDMETHOD(Activate)(HWND hWndParent, LPCRECT prc, BOOL bModal)
{
// If we don't have any objects, this method should not be called
// Note that OleCreatePropertyFrame will call Activate even if
// a call to SetObjects fails, so this check is required
if (!m_ppUnk)
return E_UNEXPECTED;
// Use Activate to update the property page's UI with information
// obtained from the objects in the m_ppUnk array
// We update the page to display the Name and ReadOnly properties
// of the document
// Call the base class
HRESULT hr = PPGBaseClass::Activate(hWndParent, prc, bModal);
if (FAILED(hr))
return hr;
// Get the EnvDTE::Document pointer
CComQIPtr<EnvDTE::Document> pDoc(m_ppUnk[0]);
if (!pDoc)
return E_UNEXPECTED;
// Get the FullName property
hr = pDoc->get_FullName(&m_bstrFullName);
if (FAILED(hr))
return hr;
// Set the text box so that the user can see the document name
USES_CONVERSION;
SetDlgItemText(IDC_NAME, CW2CT(m_bstrFullName));
// Get the ReadOnly property
m_bReadOnly = VARIANT_FALSE;
hr = pDoc->get_ReadOnly(&m_bReadOnly);
if (FAILED(hr))
return hr;
// Set the check box so that the user can see the document's read-only status
CheckDlgButton(IDC_READONLY, m_bReadOnly ? BST_CHECKED : BST_UNCHECKED);
return hr;
}
Esse código usa os métodos de através da interface de Documento para obter as propriedades que você está interessado.Usa nos wrappers da API do Win32 fornecidos por CDialogImpl e por suas classes base para exibir os valores de propriedade para o usuário.
Substituindo IPropertyPageImpl::Apply
Quando os usuários desejam aplicar as alterações aos objetos, o site da página de propriedades chamar o método de Aplicar .Este é o local para fazer o inverso de código em Ativar — enquanto Ativar recebe valores do objeto e introduziu os controles na página de propriedades, Aplicar recebe valores dos controles na página de propriedades e introdu-los no objeto.
STDMETHOD(Apply)(void)
{
// If we don't have any objects, this method should not be called
if (!m_ppUnk)
return E_UNEXPECTED;
// Use Apply to validate the user's settings and update the objects'
// properties
// Check whether we need to update the object
// Quite important since standard property frame calls Apply
// when it doesn't need to
if (!m_bDirty)
return S_OK;
HRESULT hr = E_UNEXPECTED;
// Get a pointer to the document
CComQIPtr<EnvDTE::Document> pDoc(m_ppUnk[0]);
if (!pDoc)
return hr;
// Get the read-only setting
VARIANT_BOOL bReadOnly = IsDlgButtonChecked(IDC_READONLY) ? VARIANT_TRUE : VARIANT_FALSE;
// Get the file name
CComBSTR bstrName;
if (!GetDlgItemText(IDC_NAME, bstrName.m_str))
return E_FAIL;
// Set the read-only property
if (bReadOnly != m_bReadOnly)
{
hr = pDoc->put_ReadOnly(bReadOnly);
if (FAILED(hr))
return hr;
}
// Save the document
if (bstrName != m_bstrFullName)
{
EnvDTE::vsSaveStatus status;
hr = pDoc->Save(bstrName, &status);
if (FAILED(hr))
return hr;
}
// Clear the dirty status of the property page
SetDirty(false);
return S_OK;
}
Observação |
---|
A verificação contra m_bDirty no início da implementação é uma verificação inicial para evitar atualizações desnecessárias de objetos se Aplicar é chamado mais de uma vez.Há também verificações com cada um dos valores de propriedade para garantir que somente as alterações conduzam a um chamada de método a Documento. |
Observação |
---|
Expõe FullName deDocumento como uma propriedade somente leitura.Para atualizar o nome de arquivo do documento com base nas alterações feitas na página de propriedades, você precisa usar o método de Salvar para salvar o arquivo com um nome diferente.Assim, o código em uma página de propriedades não tem que limitar-se para obter ou definir a propriedades. |
Exibindo a página de propriedades
Para exibir esta página, você precisará criar um objeto auxiliar simples.O objeto auxiliar fornecerá um método que simplifica OleCreatePropertyFrame API para exibir uma única página conectada a um único objeto.Este auxiliar será criado para que ele pode ser usado do Visual Basic.
Use Adicione a caixa de diálogo de classe e Assistente simples de objeto de ATL para gerar uma nova classe e usar Helper como seu nome curto.Uma vez criado, adicione um método conforme mostrado na tabela abaixo.
Item |
Valor |
---|---|
Nome do Método |
ShowPage |
Parâmetros |
[in] BSTR bstrCaption, [in] BSTR bstrID, [in] IUnknown* pUnk |
O parâmetro de bstrCaption é a legenda para ser exibida como o título da caixa de diálogo.O parâmetro de bstrID é uma cadeia de caracteres que representa um CLSID ou um ProgID da página de propriedades para exibir.O parâmetro de pUnk será o ponteiro de IUnknown do objeto cujas propriedades serão configuradas pela página de propriedades.
Implementar o método como mostrado abaixo:
STDMETHODIMP CHelper::ShowPage(BSTR bstrCaption, BSTR bstrID, IUnknown* pUnk)
{
if (!pUnk)
return E_INVALIDARG;
// First, assume bstrID is a string representing the CLSID
CLSID theCLSID = {0};
HRESULT hr = CLSIDFromString(bstrID, &theCLSID);
if (FAILED(hr))
{
// Now assume bstrID is a ProgID
hr = CLSIDFromProgID(bstrID, &theCLSID);
if (FAILED(hr))
return hr;
}
// Use the system-supplied property frame
return OleCreatePropertyFrame(
GetActiveWindow(), // Parent window of the property frame
0, // Horizontal position of the property frame
0, // Vertical position of the property frame
bstrCaption, // Property frame caption
1, // Number of objects
&pUnk, // Array of IUnknown pointers for objects
1, // Number of property pages
&theCLSID, // Array of CLSIDs for property pages
NULL, // Locale identifier
0, // Reserved - 0
NULL // Reserved - 0
);
}
Criando uma macro
Depois de criar o projeto, você pode testar a página de propriedades e o objeto auxiliar usando uma macro simples que você pode criar e executar no ambiente de desenvolvimento Visual Studio.Este macro criará um objeto auxiliar, então chama o método de ShowPage usando ProgID da página de propriedades de DocProperties e ponteiro de IUnknown de documento ativo no editor do Visual Studio.o código que você precisa para este macro é mostrado abaixo:
Imports EnvDTE
Imports System.Diagnostics
Public Module AtlPages
Public Sub Test()
Dim Helper
Helper = CreateObject("ATLPages7.Helper.1")
On Error Resume Next
Helper.ShowPage( _
ActiveDocument.Name, _
"ATLPages7Lib.DocumentProperties.1", _
DTE.ActiveDocument _
)
End Sub
End Module
Quando você executa esse macros, a página de propriedades será exibida mostrando o nome de arquivo e o status somente leitura do documento de texto atualmente ativa.O estado de somente leitura do documento reflete somente a capacidade de gravar o documento no ambiente de desenvolvimento; não afeta o atributo somente-leitura do arquivo no disco.