Partilhar via


Descrição geral da personalização e criação de formulários com a Ferramenta de Criação do Service Manager

Importante

Esta versão do Service Manager chegou ao fim do suporte. Recomendamos que atualize para o Service Manager 2022.

Um formulário é uma janela que permite que os utilizadores interajam com objetos a partir da base de dados. Os utilizadores podem utilizar um formulário para ver e editar as propriedades dos objetos. Cada formulário está associado a uma classe específica e apresenta informações apenas para instâncias da classe de destino. Um formulário contém campos. Normalmente, cada campo está vinculado a uma propriedade específica da classe de destino do formulário. Por exemplo, o formulário de incidente está associado ao objeto de incidente. Por conseguinte, o formulário de incidente apresenta informações sobre objetos de incidentes na base de dados.

Um formulário Service Manager consiste na implementação do formulário Windows Presentation Foundation (WPF) numa assemblagem do Microsoft .NET Framework e numa definição de formulário num pacote de gestão de Service Manager. A definição de formulário especifica a classe que o formulário representa, juntamente com as outras propriedades do formulário.

Principais conceitos sobre formulários

Antes de personalizar formulários, deve estar familiarizado com os seguintes conceitos de formulários.

Como os formulários são utilizados

Quando o pacote de gestão que contém as definições de formulário é importado para Service Manager, as definições de formulário são armazenadas na base de dados. Mais tarde, quando o utilizador iniciar uma tarefa de consola Service Manager que requer a apresentação de um objeto, Service Manager tem de encontrar um formulário para apresentar o objeto pedido. Service Manager acede à base de dados e procura um formulário que tenha sido definido para esse objeto. Se não for definido nenhum formulário para o objeto, Service Manager procura um formulário definido para o objeto principal do objeto. Service Manager continua a procurar na hierarquia de herança de todo o objeto até encontrar um formulário definido.

Formulários genéricos

Se Service Manager não conseguir encontrar qualquer formulário para o objeto ou para qualquer um dos objetos principais, Service Manager cria dinamicamente um formulário genérico predefinido para esse objeto. O formulário genérico é um formulário gerado pelo sistema que é suficiente para utilização simples de formulários. O formulário genérico representa uma forma rápida e fácil de criar um formulário para objetos sem quaisquer definições de formulário.

Por predefinição, o formulário genérico apresenta todas as propriedades do formulário num esquema simples que não pode alterar. O formulário genérico apresenta as propriedades de todos os objetos principais na hierarquia de herança do formulário e não pode alterar esse comportamento. As personalizações do formulário genérico são limitadas. Por exemplo, pode especificar as propriedades que pretende que o formulário genérico apresente; no entanto, o formulário genérico não pode ser utilizado como base para personalização. Se mais tarde definir um formulário personalizado para esse objeto, o formulário personalizado substitui o formulário genérico do objeto.

Para obter informações sobre como ocultar propriedades num formulário genérico e outras formas de personalizar um formulário genérico, consulte a publicação de blogue Descrição geral da Infraestrutura de Formulários e do Formulário Genérico.

Classes de combinação em formulários

Por vezes, é necessário um formulário para apresentar informações que derivam de mais do que uma classe. Para tal, vai criar uma classe de combinação e, em seguida, vincular um campo no formulário à classe de combinação. Para obter mais informações sobre classes de combinação, veja Alterações ao Esquema Comum do System Center.

Aspetos funcionais de um formulário

Um formulário tem os seguintes aspetos funcionais:

  1. Inicialização

  2. Size and location (Tamanho e localização)

  3. Atualizar

  4. Submeter alterações

Estes aspetos são descritos nas secções seguintes.

Inicialização

Durante a inicialização, o XAML (Extensible Application Markup Language) de um formulário é analisado e todos os controlos no formulário são instanciados e carregados. O evento Carregado do formulário indica quando o formulário e todos os elementos contidos foram carregados. As operações de carregamento de dados são assíncronas. Por conseguinte, a instância de destino pode não estar disponível quando o evento Carregado é gerado. Em vez disso, o evento DataContextChanged tem de ser utilizado para notificação quando a instância de destino estiver definida para o formulário. O evento PropertyChanged da propriedade DataContext pode ser utilizado em vez do evento DataContextChanged .

Recomendamos que utilize o evento Carregado para inicialização personalizada relacionada com o controlo e, em seguida, utilize os eventos DataContextChanged ou PropertyChanged na propriedade DataContext para inicialização personalizada relacionada com instâncias de destino.

Size and location (Tamanho e localização)

Quando um formulário é apresentado numa janela de pop-up, o tamanho inicial é determinado com base nas propriedades Largura, Altura, MinWidth e MinHeight do formulário. Se estas propriedades não estiverem definidas para o formulário, o tamanho inicial do formulário é calculado com base no respetivo conteúdo.

Recomendamos que defina estas propriedades do seguinte modo:

  • Defina as propriedades Largura e Altura do formulário para especificar explicitamente o tamanho ideal. Considere definir estas propriedades para o valor Automático . Isto define a largura e altura do formulário com base no tamanho do conteúdo.

  • Defina as propriedades MinWidth e MinHeight do formulário para especificar a janela mais pequena aceitável para o formulário. Se um utilizador redimensionar a janela para um tamanho mais pequeno do que o especificado, são apresentadas barras de deslocamento para deslocar-se para o conteúdo oculto do formulário.

Quando o formulário é alojado no anfitrião de formulários Service Manager, o tamanho e a localização utilizados pela última vez são preservados para posterior apresentação desse formulário pelo mesmo utilizador na mesma sessão de execução.

Atualizar

A instância de destino de um formulário pode ser alterada como resultado da execução de um comando Atualizar no formulário. O processador para este comando obtém dados novos da base de dados. Quando os dados chegam, o valor da propriedade DataContext do formulário é definido para a nova instância de destino e o evento DataContextChanged é gerado.

Para diferenciar entre o evento DataContextChanged que foi gerado quando o formulário foi carregado pela primeira vez e o evento que foi gerado para processar um comando Atualizar , verifique a propriedade OldValue dos argumentos de evento que são transmitidos com o evento. Esta propriedade é nula se o formulário tiver acabado de ser inicializado.

Submeter alterações

A janela de pop-up do anfitrião de formulários no Service Manager fornece botões para submeter as alterações efetuadas no formulário e para fechar a janela de pop-up.

Quando um utilizador seleciona o botão Aplicar para um formulário, a instância de destino do formulário é submetida para armazenamento. Esta operação é síncrona; Por conseguinte, o utilizador não pode editar o formulário até que a operação de submissão esteja concluída. Se ocorrer uma falha durante a submissão de formulários, surge uma mensagem de erro. O formulário permanece aberto para outras alterações. Recomenda-se que os utilizadores apliquem frequentemente as alterações efetuadas para evitar colisões se outra instância do formulário estiver a ser editada em simultâneo.

Se o utilizador selecionar o botão OK , o comportamento é semelhante a Aplicar, exceto que, se a operação de submissão do formulário for bem-sucedida, o formulário e a janela do anfitrião serão fechados.

Se o utilizador selecionar o botão Cancelar , é apresentada uma caixa de diálogo que pede ao utilizador para confirmar a operação. O utilizador pode selecionar Sim e perder alterações ou selecionar Não e voltar ao formulário.

Diretrizes gerais e melhores práticas para formulários

Pode expandir as funcionalidades de Service Manager ao adicionar ou modificar formulários. Esta secção descreve algumas recomendações de melhores práticas para criar e utilizar formulários Service Manager, utilizando diretamente várias ferramentas e definições de formulários de scripting.

Esta secção destina-se principalmente a parceiros e clientes que tenham experiência na criação dos seus próprios formulários personalizados com Windows Presentation Foundation (WPF) e o Microsoft Visual Studio Team System ou o Microsoft Expression Blend.

As diretrizes gerais para criar um novo formulário são as seguintes.

  • Utilizar controlos padrão.
  • Seguir as diretrizes gerais de conceção de formulários.
  • Evite o código para trás.
  • Incluir processamento de exceções.
  • Considerar personalizações e atualizações de formulários.
  • Atribuir nomes a todos os controlos personalizáveis.
  • Associar o formulário a origens de dados.
  • Utilize Service Manager regras de validação da infraestrutura de formulários, conversores de valores e modelos de erro.
  • Utilizar comandos e eventos de infraestrutura de formulários.

Para obter informações sobre estas diretrizes, consulte as secções seguintes.

Utilizar controlos padrão

Os controlos utilizados num formulário podem ser:

  • Controlos padrão. Entre eles incluem-se controlos da biblioteca .NET, tais como a caixa de combinação e a caixa de listagem.
  • Controlos personalizados. Entre eles incluem-se os controlos adicionais criados pelo autor do formulário ou por terceiros.

Dica

Se utilizar controlos padrão e evitar, na medida do possível, a criação de controlos personalizados, estará a contribuir para a consistência na experiência do utilizador com formulários. Se tiver de criar um controlo personalizado, separe o comportamento e a aparência visual do comportamento lógico utilizando modelos de controlo para definir a aparência do controlo. De preferência, deve existir um modelo de controlo separado para cada Tema do Windows.

Siga as diretrizes gerais de conceção de formulários

Quando criar um formulário, utilize as diretrizes de design público para garantir que o formulário é amigável para o utilizador e que cumpre paradigmas comuns de interação de utilizadores.

Para obter mais informações sobre a estrutura geral do Windows, veja Diretrizes de Interação da Experiência do Utilizador do Windows.

Além disso:

  • Divida as informações entre vários separadores para que o formulário seja mais simples e fácil de ler. Inclua as informações mais utilizadas no primeiro separador e informações de menor importância nos separadores subsequentes.
  • Utilize os painéis de esquema para dispor os controlos no formulário. Isto garante que o formulário se comporta corretamente quando é redimensionado e localizado.
  • Evite definir propriedades visuais para controlos individuais e opte por utilizar estilos. Isto permite-lhe alterar o aspeto de todos os controlos numa série de formas ao modificar o estilo e promove um aspeto consistente entre formas relacionadas.

Evitar código para trás

Code-behind é um termo que descreve o código que é associado a objetos definidos por markup quando uma página XAML é compilada. Limite o máximo possível a utilização de código para trás num formulário. É preferível que tenha incorporado o código de um formulário no próprio controlo, porque mais tarde é mais fácil alterar esse código. Em vez disso, utilize as capacidades declarativas suportadas pela infraestrutura de formulários Service Manager para definir as conversões de valores e as regras de validação no formulário.

Como orientação geral, deve limitar a utilização do código atrasado a situações em que não é possível fornecer a funcionalidade necessária através das capacidades declarativas do XAML, com classes definidas no WPF e na biblioteca de infraestrutura de formulários. Mesmo assim, considere mover a funcionalidade implementada no code-behind para uma biblioteca auxiliar e, em seguida, referenciar a partir do XAML.

Incluir o processamento de exceções

Certifique-se de que o código no formulário contém o processamento de exceções para que o formulário possa ser carregado durante a fase de estrutura na Ferramenta de Criação e na consola do Service Manager no tempo de execução.

Considerar a personalização e atualizações de formulários

Quando estiver a criar um novo formulário, deve considerar futuras personalizações e atualizações para esse formulário. Para garantir que é possível personalizar e atualizar um formulário ao preservar personalizações, siga as diretrizes e sugestões fornecidas anteriormente nesta secção, juntamente com as seguintes diretrizes:

  • Considere personalizações e atualizações futuras mais cedo enquanto estiver a estruturar o formulário. É provável que os formulários evoluam em versões futuras e é importante considerar como os utilizadores poderão atualizar para novas versões do seu formulário, preservando as respetivas personalizações para o formulário original. Por exemplo, é possível fornecer um formulário atualizado depois de os utilizadores já terem investido muito tempo na personalização do formulário original. Os utilizadores esperam que as personalizações efetuadas se mantenham após a atualização da versão.

  • Fornecer um nome exclusivo a cada controlo no formulário para que as personalizações possam ser aplicadas aos controlos. As personalizações de formulários são armazenadas como um conjunto de ações destinadas a um controlo específico ou a um conjunto de controlos. O controlo de destino é referenciado pelo nome, razão pela qual é importante preservar os nomes de controlo entre versões do formulário. Se um controlo não tiver um nome, a Personalização de Formulários Revisor gera um nome, mas o nome gerado não é preservado em diferentes versões do formulário.

  • Certifique-se de que os nomes de controlo permanecem imutáveis em diferentes versões do formulário. Deste modo, torna-se possível garantir que as personalizações de um determinado controlo numa versão anterior podem ser aplicadas ao mesmo controlo numa nova versão do formulário.

  • Se possível, ao atualizar um formulário, evitar mover controlos para uma localização diferente no mesmo separador. Uma das personalizações mais comuns aplicadas pelo utilizador é mover os controlos no formulário para uma localização diferente. Se alterar a localização de um controlo numa nova versão do formulário, existe o risco de a nova localização de controlo se sobrepor a um controlo que o utilizador tenha relocalizado.

  • Se possível, evite mover controlos entre separadores quando estiver a conceber uma atualização para um formulário existente. Os controlos são identificados pelo nome e pelo separador no qual estão localizados. Mover um controlo de um separador para outro numa nova versão do formulário pode anular as personalizações aplicadas pelo utilizador a esse controlo, porque as personalizações não conseguirão identificar o controlo de destino.

  • Quando a atualização para um formulário incluir novos controlos, considere adicionar os novos controlos a um novo separador. Esta é a forma mais segura de evitar interferir com quaisquer personalizações de utilizador nos separadores e controlos existentes.

  • Ter em conta o modo como os controlos estão associados. Os controlos só de leitura devem utilizar apenas enlaces unidirecionais.

Atribuir um nome a todos os controlos personalizáveis

Certifique-se de que os nomes dos controlos descrevem a que dados é que os controlos estão associados ou qual a função de cada controlo.

Vincular o formulário a origens de dados

O principal objetivo de um formulário é visualizar um único objeto a partir da base de dados Service Manager. Este objeto é denominado instância de destino, que é sempre especificada pela propriedade DataContext de um formulário (que é herdado da classe FrameworkElement ).

Importante

Não modifique a propriedade DataContext do formulário. O ambiente de alojamento dos formulários utiliza esta propriedade para identificar a instância de destino do formulário.

No modelo de dados Service Manager, uma instância de destino é representada como um objeto BindableDataItem. Esta classe agrega o objeto do kit de desenvolvimento de software (SDK) subjacente e expõe as respetivas propriedades através de um indexador, que assume um nome de propriedade como parâmetro.

A classe BindableDataItem também implementa ICustomTypeDescriptor, o que permite utilizar a classe BindableDataItem como uma origem de dados para o enlace WPF. Segue-se um exemplo de enlace de uma propriedade de instância de destino à propriedade Text de um controlo TextBox :


<TextBox Name="textBoxDescription" Text="{Binding Path=Summary}"/>

Não é necessário especificar a Origem do enlace porque as instâncias de destino estão definidas como DataContext do formulário, que funciona como a Origem predefinida para todos os controlos no formulário.

Os controlos no formulário podem ser vinculados a origens de dados que não a instância de destino e a biblioteca de infraestrutura de formulários contém muitos controlos que executam o enlace implicitamente. Por exemplo, o controlo de selecionador de instâncias está associado à origem de dados que fornece uma coleção de instâncias à escolha. Também é possível definir origens de dados adicionais declarativamente com as classes ObjectDataProvider e XmlDataProvider .

A infraestrutura de formulários considera a instância de destino como a única origem de dados de leitura/escrita no formulário. Por conseguinte, a implementação do comando Submeter só armazenará as alterações efetuadas à instância de destino. As outras origens de dados do formulário serão tratadas como só de leitura.

Utilizar regras de validação da infraestrutura de formulários Service Manager, conversores de valores e modelos de erro

Recomendamos que utilize regras de validação da infraestrutura de formulários em formulários para designar entradas de dados que não são válidas. A infraestrutura de enlace WPF suporta a validação de propriedades de controlo vinculadas a uma origem de dados com enlaces unidirecionais ou bidirecionais. O objeto de enlace tem uma coleção ValidationRules que pode conter qualquer número de objetos ValidationRule . Sempre que os dados são enviados do controlo para a origem de dados, os objetos ValidationRule são chamados para validar o valor.

A biblioteca de infraestrutura de formulários contém muitas regras de validação que lidam com os casos mais comuns. A infraestrutura de formulários aproveita as regras de validação para determinar se o conteúdo dos formulários pode ser submetido para armazenamento. Por exemplo, o botão Submeter de um formulário pode ser desativado se existir um controlo que tenha um erro de validação no formulário.

É recomendável utilizar o modelo de erro personalizado fornecido com a biblioteca de infraestrutura de formulários. Se um controlo tiver um erro de validação, aparece, por predefinição, com um rebordo vermelho à volta. O WPF permite definir um indicador de erro personalizado através da propriedade Validation.ErrorTemplate , que pode ser definida em qualquer controlo. A biblioteca de infraestrutura de formulários Service Manager contém um modelo de erro personalizado, que apresenta um ícone de erro em vez do limite vermelho WPF. Além disso, quando se aponta o rato para o ícone de erro, aparece uma descrição com uma mensagem de erro. A mensagem de erro deve indicar o motivo pelo qual não foi possível validar os dados no controlo.

O exemplo seguinte mostra como fazer referência ao modelo de erro em XAML:


<TextBox Text="{Binding SomeProperty}"
         scwpf:Validation.ValueRequired="True"
         Validation.ErrorTemplate="{DynamicResource {ComponentResourceKey {x:Type scwpf:Validation}, InvalidDataErrorTemplate}}"/>

Se as regras de validação incorporadas não fornecerem a lógica de validação necessária, recomendamos que crie regras de validação personalizadas para representar essa lógica. Deste modo, as lógicas de validação padrão e personalizada poderão coexistir no mecanismo comum de controlo de validações.

Se o mecanismo de regras de validação não for adequado para um cenário específico, deve, em vez disso, processar FormEvents.PreviewSubmitEvent e executar a validação a partir daí.

No exemplo de código seguinte é fornecido um exemplo do padrão que pode ser utilizado para executar uma validação personalizada:


void MyForm_Loaded(object sender, RoutedEventArgs e)
{
    // hook to handle form events
    this.AddHandler(
        FormEvents.PreviewSubmitEvent,
        new EventHandler<PreviewFormCommandEventArgs>(this.OnPreviewSubmit));
}
private void OnPreviewSubmit(object sender, PreviewFormCommandEventArgs e)
{
    string errorMessage;
    bool result = this.DoVerify(out errorMessage);
    if (!result)
    {
        // cancel Submit operation
        e.Cancel = true;
        // display error message
        MessageBox.Show(errorMessage);
    }
}
internal bool DoVerify(out string errorMessage)
{
    // Do custom verification and return true to indicate that
    // validation check has passed; otherwise return false and
    // populate errorMessage argument
}

Utilizar comandos e eventos da infraestrutura de formulários

A infraestrutura de formulários expõe muitos comandos que podem ser executados num formulário. Entre estes comandos incluem-se os seguintes:

  • FormsCommand.Submit, que guarda a instância de destino do formulário.

  • FormsCommand.SubmitAndClose, que guarda a instância de destino do formulário e fecha o formulário.

  • FormsCommand.Refresh, que repete a consulta para a instância de destino do formulário.

  • FormCommands.Cancel, que elimina todas as alterações e fecha o formulário.

Os eventos, gerados antes e depois da execução do comando, mostram cada um destes comandos entre parêntesis.

Os eventos seguintes são gerados antes do comando:

  • O evento FormEvents.PreviewSubmit é gerado antes do comando FormCommand.Submit e o evento FormEvents.Submited é gerado após o comando FormCommand.Submit .

  • O evento FormEvents.PreviewRefresh é gerado antes do comando FormCommands.Refresh e o comando FormCommand.Refreshed é gerado após o comando FormCommand.Submit .

  • O evento FormEvents.PreviewCancel é gerado antes do comando FormCommands.Cancel e o evento FormCommand.Canceled é gerado após o comando FormCommand.Cancel .

Os eventos de pré-visualização passam por um objeto PreviewFormCommandEventArgs . Este objeto contém uma propriedade Cancel mutável que impedirá a execução do comando correspondente quando a propriedade estiver definida como true.

Os eventos pós-comando passam um objeto FormCommandExecutedEventArgs . Este objeto contém uma propriedade Resultado que indica se a execução do comando foi cancelada ou se causou um erro. Em caso de erro, a propriedade Erro do objeto FormCommandExecutedEventArgs referencia a exceção que fornece informações sobre o erro.

É possível ativar, desativar e executar comandos de formulário de forma programática e declarativa.

Para ativar comandos de formulário através de programação, estabeleça um CommandBinding entre o formulário e o comando relacionado.

No exemplo seguinte, é estabelecido um enlace de comando entre o formulário e um comando Atualizar e são definidos dois processadores para este comando. O primeiro processador devolve se o comando Atualizar pode ou não ser executado e o segundo processador contém, na verdade, a implementação do comando Atualizar :


    public class MyForm : UserControl
    {
        public MyForm()
        {
            // do standard initialization
            // establish CommandBinding for Refresh command
            this.CommandBindings.Add(
                new CommandBinding(FormCommands.Refresh, this.ExecuteRefresh, this.CanExecuteRefresh));
        }
        private void CanExecuteRefresh(
              object sender,
              CanExecuteRoutedEventArgs e)
        {
            // put your logic that determines whether Refresh
// can be executed here
            bool canExecute = true;
            BindableDataItem dataItem = this.DataContext as BindableDataItem;
            if (dataItem)
            {
                canExecute = dataItem["Status"] != "New";
            }
            e.CanExecute = canExecute;
        }
        private void ExecuteRefresh(
            object sender,
            ExecutedRoutedEventArgs e)
        {
            // here is placeholder for the code that has do be
// executed upon running Refresh command
        }
    }

Pode também definir processadores para comandos de formulário de modo declarativo. Pode fazê-lo ao utilizar um objeto Regra que utiliza um RoutedCommandTrigger. O exemplo de código seguinte mostra como definir processadores de modo declarativo:


    <scwpf:BusinessLogic.Rules>
        <scwpf:RuleCollection>
            <scwpf:Rule>
                <scwpf:Rule.Triggers>
                    <scwpf:RoutedCommandTrigger
RoutedCommand="{x:Static scwpf:FormCommands.Refresh}"/>
                </scwpf:Rule.Triggers>
                <scwpf:Rule.Conditions>
                    <scwpf:PropertyMatchCondition
                        Binding="{Binding Status}"
                        Value="New"
                        Operation="NotEquals" />
                </scwpf:Rule.Conditions>
                <!-- Use RuleAction objects to define the logic that executed
                upon running Refresh command; this can be left empty -->
            </scwpf:Rule>
        </scwpf:RuleCollection>
    </scwpf:BusinessLogic.Rules>

Passos seguintes