Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
O assistente de Páginas de Propriedades ATL não está disponível no Visual Studio 2019 e posterior.
Este exemplo mostra como criar uma página de propriedades que exibe (e permite alterar) propriedades da interface Classes de Documento .
O exemplo é baseado no exemplo ATLPages.
Para completar este exemplo, você irá:
Adicione a classe de página de propriedades ATL usando a caixa de diálogo Adicionar classe e o Assistente de página de propriedades ATL.
Edite o recurso de diálogo adicionando novos controles para as propriedades interessantes da
Documentinterface.Adicione manipuladores de mensagens para manter o site da página de propriedades informado sobre as alterações feitas pelo usuário.
Adicione algumas
#importdeclarações e um typedef na seção Housekeeping.Sobrescreva IPropertyPageImpl::SetObjects para validar os objetos a serem passados para a página de propriedades.
Substitua IPropertyPageImpl::Activate para inicializar a interface da página de propriedades.
Override IPropertyPageImpl::Apply para atualizar o objeto com os valores de propriedade mais recentes.
Exiba a página de propriedades criando um objeto auxiliar simples.
Crie uma macro que testará a página de propriedades.
Adicionando a classe de página de propriedade ATL
Primeiro, crie um novo projeto ATL para um servidor DLL chamado ATLPages7. Agora use o ATL Property Page Wizard para gerar uma página de propriedades. Dê à página de propriedades um Nome Curto de DocProperties e, em seguida, alterne para a página Strings para definir itens específicos da página de propriedades, conforme mostrado na tabela abaixo.
| Iteme | Valor |
|---|---|
| Título | Documento de texto |
| String de documentos | Propriedades do Documento de Texto VCUE |
| Ficheiro de ajuda | <em branco> |
Os valores definidos nesta página do assistente serão retornados ao contêiner da página de propriedades quando ele chamar IPropertyPage::GetPageInfo. O que acontece com as cadeias de caracteres depois disso depende do contêiner, mas normalmente elas serão usadas para identificar sua página para o usuário. O Título geralmente aparecerá em uma guia acima da sua página e a Cadeia de Caracteres do Documento pode ser exibida em uma barra de status ou Dica de Ferramentas (embora o quadro de propriedade padrão não use essa cadeia de caracteres).
Observação
As cadeias de caracteres definidas aqui são armazenadas como recursos de cadeia de caracteres em seu projeto pelo assistente. Você pode editar facilmente essas cadeias de caracteres usando o editor de recursos se precisar alterar essas informações depois que o código da sua página tiver sido gerado.
Clique em OK para que o assistente gera a sua página de propriedades.
Editando o recurso de diálogo
Agora que sua página de propriedade foi gerada, você precisará adicionar alguns controles ao recurso 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 suas IDs conforme mostrado abaixo:
Esses elementos de controlo serão usados para exibir o nome do ficheiro do documento e o seu estado de somente leitura.
Observação
O recurso de diálogo não inclui um quadro ou botões de comando, nem tem a aparência em abas que se poderia esperar. Esses recursos são fornecidos por uma moldura de página de propriedade, como a criada chamando OleCreatePropertyFrame.
Adicionando manipuladores de mensagens
Com os controles instalados, você pode adicionar manipuladores de mensagens para atualizar o status sujo da página quando o valor de qualquer um dos controles for alterado:
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 no controle de edição ou na caixa de seleção chamando IPropertyPageImpl::SetDirty, que informa ao site da página que a página foi alterada. Normalmente, o site da página responderá ativando ou desativando um botão Aplicar no quadro da página de propriedades.
Observação
Em suas próprias páginas de propriedades, talvez seja necessário controlar com precisão quais propriedades foram alteradas pelo usuário para evitar a atualização de propriedades que não foram alteradas. Este exemplo implementa esse código controlando os valores de propriedade originais e comparando-os com os valores atuais da interface do usuário quando é hora de aplicar as alterações.
Manutenção
Agora, adicione algumas #import instruções a DocProperties.h para que o compilador saiba sobre a Document interface:
// 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á se referir à IPropertyPageImpl classe base, adicione o seguinte typedef à CDocProperties classe:
typedef IPropertyPageImpl<CDocProperties> PPGBaseClass;
Sobrepondo IPropertyPageImpl::SetObjects
O primeiro IPropertyPageImpl método que você precisa substituir é SetObjects. Aqui você adicionará código para verificar se apenas um único objeto foi passado e se ele suporta a Document interface que você espera:
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 suportar apenas um único objeto para esta página porque você permitirá que o usuário defina o nome do arquivo do objeto — apenas um arquivo pode existir em qualquer local.
Substituindo IPropertyPageImpl::Ativar
A próxima etapa é inicializar a página de propriedades com os valores de propriedade do objeto subjacente quando a página for criada pela primeira vez.
Nesse caso, você deve adicionar os seguintes membros à classe, pois também usará os valores de propriedade iniciais para comparação quando os usuários da página aplicarem suas 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 Activate é responsável pela criação da caixa de diálogo e seus controles, para que você possa substituir esse método e adicionar sua própria inicialização depois de 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 COM da Document interface para obter as propriedades nas quais você está interessado. Em seguida, ele usa os wrappers de API do Win32 fornecidos por CDialogImpl e suas classes base para exibir os valores de propriedade para o usuário.
Substituindo/Redefinindo IPropertyPageImpl::Apply
Quando os usuários quiserem aplicar suas alterações aos objetos, o site da página de propriedades chamará o método Apply . Este é o lugar para fazer o inverso do código em Activate — enquanto Activate pegou valores do objeto e os empurrou para os controles na página de propriedades, Apply pega valores dos controles na página de propriedades e os envia para o 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 desta implementação é uma verificação inicial para evitar atualizações desnecessárias dos objetos se Apply for chamada mais de uma vez. Também há verificações em relação a cada um dos valores de propriedade para garantir que apenas as alterações resultem em uma chamada de método para o Document.
Observação
Document expõe FullName como uma propriedade só de leitura. Para atualizar o nome do arquivo do documento com base nas alterações feitas na página de propriedades, você precisa usar o Save método para salvar o arquivo com um nome diferente. Assim, o código em uma página de propriedades não precisa se limitar a obter ou definir propriedades.
Exibindo a página de propriedades
Para exibir esta página, você precisa criar um objeto auxiliar simples. O objeto auxiliar fornecerá um método que simplifica a API para exibir uma única página conectada OleCreatePropertyFrame a um único objeto. Este auxiliar será projetado para que ele possa ser usado a partir do Visual Basic.
Use a caixa de diálogo Adicionar classe e o ATL Simple Object Wizard para gerar uma nova classe e usar Helper como seu nome abreviado. Uma vez criado, adicione um método como mostrado na tabela abaixo.
| Iteme | Valor |
|---|---|
| Nome do método | ShowPage |
| Parâmetros | [in] BSTR bstrCaption, [in] BSTR bstrID, [in] IUnknown* pUnk |
O parâmetro bstrCaption é a legenda a ser exibida como o título da caixa de diálogo. O parâmetro bstrID é uma cadeia de caracteres que representa um CLSID ou um ProgID da página de propriedades a ser exibida. O parâmetro pUnk será o IUnknown ponteiro do objeto cujas propriedades serão configuradas pela página de propriedades.
Implemente 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 do Visual Studio. Essa macro criará um objeto auxiliar e, em seguida, chamará seu ShowPage método usando o ProgID da página de propriedades DocProperties e o IUnknown ponteiro do documento atualmente ativo no editor do Visual Studio. O código que você precisa para esta 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ê executar essa macro, a página de propriedades será exibida, mostrando o nome do ficheiro e o estado apenas de leitura do documento de texto ativo no momento. O estado somente leitura do documento reflete apenas a capacidade de gravar no documento no ambiente de desenvolvimento; ele não afeta o atributo somente leitura do arquivo no disco.