Compartilhar via


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çãoObservaçã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.

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:

Recurso de diálogo de edição do Visual Studio

Esses controles serão usados para exibir o nome de arquivo do documento e de seu status somente leitura.

ObservaçãoObservaçã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çãoObservaçã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çãoObservaçã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çãoObservaçã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çãoObservaçã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.

Consulte também

Conceitos

Páginas de propriedades de ATL COM

exemplo de ATLPages