Partilhar via


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

Um formulário é uma janela que possibilita que os usuários interajam com objetos do banco de dados. Os usuários podem usar um formulário para exibir e editar as propriedades dos objetos. Cada formulário está vinculado a uma classe específica e exibe informações apenas para instâncias da classe de destino. Um formulário contém campos. Normalmente, cada campo é vinculado a uma propriedade específica da classe de destino do formulário. O formulário de incidente, por exemplo, está vinculado ao objeto incidente. Portanto, o formulário de incidente exibe informações sobre objetos de incidente no banco de dados.

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

Conceitos-chave sobre formulários

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

Utilização de formulários

Quando o pacote de gerenciamento que contém as definições de formulário é importado para o Service Manager, as definições de formulário são armazenadas no banco de dados. Mais tarde, quando o usuário inicia uma tarefa do Console do Service Manager que requer a exibição de um objeto, o Service Manager deve encontrar um formulário para exibir o objeto solicitado. O Service Manager acessa o banco de dados e procura um formulário que foi definido para esse objeto. Se nenhum formulário for definido para o objeto, o Service Manager procurará um formulário definido para o objeto pai do objeto. O Service Manager continua a pesquisar toda a hierarquia de herança do objeto até encontrar um formulário definido.

Formulários genéricos

Se o Service Manager não conseguir encontrar nenhum formulário para o objeto ou para qualquer um de seus objetos pai, o Service Manager criará dinamicamente um formulário padrão genérico para esse objeto. O formulário genérico é um formulário gerado pelo sistema que é suficiente para o uso simples do formulário. O formulário genérico representa uma maneira rápida e fácil de criar um formulário para objetos sem nenhuma definição de formulário.

Por padrão, o formulário genérico exibe todas as propriedades do formulário em um layout simples que não pode ser alterado. O formulário genérico exibe as propriedades de todos os objetos pai na hierarquia de herança do formulário e você não pode alterar esse comportamento. As personalizações para o formulário genérico são limitadas. Por exemplo, você pode especificar as propriedades que deseja que o formulário genérico exiba; no entanto, o formulário genérico não pode ser usado como base para personalização. Se, posteriormente, você definir um formulário personalizado para esse objeto, o formulário personalizado substituirá o formulário genérico do objeto.

Para obter informações sobre como ocultar propriedades em um formulário genérico e outras maneiras de personalizar um formulário genérico, consulte a postagem do blog Visão geral da infraestrutura de formulários e o formulário genérico.

Classes de combinação em formulários

Às vezes, você precisa de um formulário para exibir informações derivadas de mais de uma classe. Para fazer isso, crie uma classe de combinação e, em seguida, vincule um campo no formulário à classe de combinação. Para obter mais informações sobre classes de combinação, consulte Alterações ao System Center Common Schema.

Aspetos funcionais de um formulário

Um formulário tem os seguintes aspetos funcionais:

  1. Inicialização

  2. Tamanho e localização

  3. Atualizar

  4. Enviar alterações

Esses aspetos são descritos nas seções a seguir.

Inicialização

Durante a inicialização, a linguagem XAML (Extensible Application Markup Language) de um formulário é analisada e todos os controles no formulário são instanciados e carregados. O evento Loaded 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. Portanto, a instância de destino poderá não estar disponível quando o evento Loaded for gerado. Em vez disso, o evento DataContextChanged deve ser usado para notificação quando a instância de destino é definida para o formulário. O evento PropertyChanged para a propriedade DataContext pode ser usado no lugar do evento DataContextChanged.

Recomendamos que você use o evento Loaded para inicialização personalizada relacionada ao controle e, em seguida, use os eventos DataContextChanged ou PropertyChanged na propriedade DataContext para inicialização personalizada relacionada à instância de destino.

Tamanho e localização

Quando um formulário é apresentado numa janela pop-up, o seu tamanho inicial é determinado com base nas propriedades Width, Height, MinWidthe MinHeight. Se essas propriedades não estiverem definidas para o formulário, o tamanho inicial do formulário será calculado com base em seu conteúdo.

Recomendamos que você defina essas propriedades da seguinte maneira:

  • Defina as propriedades Width e Height do formulário para especificar explicitamente o tamanho ideal. Considere definir essas propriedades para o valor Auto. Isso define a largura e a altura do formulário com base no tamanho do conteúdo.

  • Defina as propriedades MinWidth e MinHeight do formulário para especificar as menores dimensões aceitáveis do formulário. Se um usuário redimensionar a janela para um tamanho menor do que o especificado, as barras de rolagem aparecerão para rolar até o conteúdo do formulário oculto.

Quando o formulário é hospedado dentro do host de formulários do Service Manager, o tamanho e o local usados pela última vez são preservados para exibição subsequente desse formulário pelo mesmo usuário 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 Refresh no formulário. O manipulador para este comando busca novos dados do banco de dados. Quando os dados chegam, o valor da propriedade DataContext do formulário é definido como 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 manipular um comando Refresh, verifique a propriedade OldValue dos argumentos de evento que são passados com o evento. Esta propriedade é nula se o formulário acabou de ser inicializado.

Enviar alterações

A janela pop-up do host do formulário no Service Manager disponibiliza botões para submeter as alterações efetuadas no formulário e para fechar a janela pop-up.

Quando um usuário seleciona o botão Aplicar para um formulário, a instância de destino do formulário é enviada para armazenamento. Esta operação é síncrona; portanto, o usuário não pode editar o formulário até que a operação de envio seja concluída. Se ocorrer uma falha durante o envio do formulário, será exibida uma mensagem de erro. O formulário permanece aberto para novas alterações. Recomendamos que os usuários apliquem suas alterações com frequência para evitar colisões se outra instância do formulário estiver sendo editada ao mesmo tempo.

Se o usuário selecionar o botão OK, o comportamento será semelhante ao Apply, exceto que, se a operação de envio do formulário for bem-sucedida, o formulário e sua janela de host serão fechados.

Se o usuário selecionar o botão Cancelar, será exibida uma caixa de diálogo solicitando que o usuário confirme a operação. O usuário pode selecionar Sim e perder alterações, ou selecionar Não e retornar ao formulário.

Diretrizes gerais e práticas recomendadas para formulários

Você pode estender os recursos do Service Manager adicionando ou modificando formulários. Esta seção descreve algumas recomendações de práticas recomendadas para criar e usar formulários do Service Manager, usando várias ferramentas e definições de formulário de script diretamente.

Esta seção destina-se principalmente a parceiros e clientes experientes na criação de seus próprios formulários personalizados usando o Windows Presentation Foundation (WPF) e o Microsoft Visual Studio Team System ou o Microsoft Expression Blend.

As orientações gerais para a criação de um novo formulário são as seguintes.

  • Use controles padrão.
  • Siga as diretrizes gerais de design de formulário.
  • Evite usar 'code-behind'.
  • Inclua o tratamento de exceções.
  • Considere a personalização e as atualizações de formulários.
  • Nomeie todos os controles personalizáveis.
  • Vincule o formulário a fontes de dados.
  • Utilize as regras de validação de infraestrutura dos formulários do Service Manager, os conversores de valores e os modelos de erro.
  • Utilize comandos e eventos de infraestrutura de formulários.

Para obter informações sobre essas diretrizes, consulte as seções a seguir.

Usar controles padrão

Os controles usados em um formulário podem ser:

  • Controles padrão. Isso inclui controles de biblioteca .NET, como caixa de combinação e caixa de listagem.
  • Controles personalizados. Isso inclui controles adicionais que são criados pelo autor do formulário ou por terceiros.

Dica

Quando você usa controles padrão sempre que possível e evita a criação de controles personalizados, você promove a consistência em relação à experiência do usuário de formulários. Se você precisar criar um controle personalizado, separe a aparência visual e o comportamento e o comportamento lógico usando modelos de controle para definir a aparência do controle. De preferência, deve haver um modelo de controle separado para cada tema do Windows.

Siga as diretrizes gerais de design de formulário

Ao criar um formulário, use diretrizes de design público para garantir que o formulário seja fácil de usar e que siga paradigmas comuns de interação do usuário.

Para obter mais informações sobre o design geral do Windows, consulte Diretrizes de interação da experiência do usuário do Windows.

Além disso:

  • Divida as informações em várias guias para tornar o formulário mais simples e fácil de ler. Inclua as informações mais utilizadas no primeiro separador e as informações de menor importância nos separadores subsequentes.
  • Use painéis de layout para dispor controles no formulário. Isso garante que o formulário se comporte corretamente quando é redimensionado e localizado.
  • Evite definir propriedades visuais de controle individuais e use estilos. Isso torna possível alterar a aparência de todos os controles em uma série de formulários, modificando o estilo, e promove uma aparência consistente entre formulários relacionados.

Evite usar código por trás

Code-behind é um termo que descreve o código que é associado a objetos definidos por marcação quando uma página XAML é compilada como markup. Limite ao máximo o uso de code-behind em um formulário. É preferível que você incorpore o código para um formulário no próprio controle, porque mais tarde é mais fácil alterar esse código. Em vez disso, use os recursos declarativos suportados pela infraestrutura de formulários do Service Manager para definir conversões de valor e regras de validação no formulário.

Como diretriz geral, você deve limitar o uso de code-behind a situações nas quais não é possível fornecer a funcionalidade necessária usando os recursos declarativos de 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, faça referência a ela a partir do XAML.

Incluir tratamento de exceções

Verifique se o código no formulário contém tratamento de exceções para que o formulário possa ser carregado durante a fase de design na Ferramenta de Criação e no Console do Service Manager em tempo de execução.

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

Ao criar um novo formulário, você deve considerar futuras personalizações e atualizações para esse formulário. Para garantir que seja possível personalizar e atualizar um formulário preservando as personalizações, siga as diretrizes e dicas fornecidas anteriormente nesta seção, juntamente com as seguintes diretrizes:

  • Considere futuras personalizações e atualizações com antecedência enquanto estiver criando o formulário. É provável que os formulários evoluam em versões futuras, e é importante considerar como os usuários poderão atualizar para novas versões do formulário, preservando suas personalizações para o formulário original. Por exemplo, você pode fornecer um formulário atualizado depois que os usuários já investiram pesado na personalização do formulário original. Os usuários esperam que suas personalizações sobrevivam à atualização de versão.

  • Forneça um nome exclusivo para cada controle no formulário para possibilitar que personalizações sejam aplicadas aos controles. As personalizações de formulário são armazenadas como um conjunto de ações destinadas a um controle específico ou a um conjunto de controles. O controle de destino é referenciado por nome, e é por isso que é importante preservar nomes de controle em todas as versões do formulário. Se um controle não tiver um nome, o Editor de Personalização de Formulário gerará um nome, mas o nome gerado não será preservado em diferentes versões do formulário.

  • Certifique-se de que os nomes de controle permaneçam imutáveis em diferentes versões do formulário. Isso garante que as personalizações para um determinado controle em uma versão anterior possam ser aplicadas ao mesmo controle em uma nova versão do formulário.

  • Se possível, evite mover controles para um local diferente na mesma guia ao atualizar um formulário. Uma personalização de usuário comum é mover controles no formulário para um local diferente. Se você alterar o local de um controle em uma nova versão do formulário, há um risco de que o novo local de controle possa se sobrepor a um controle que o usuário realocou.

  • Se possível, evite mover controles entre guias ao criar uma atualização para um formulário existente. Os controles são identificados pelo nome e pela guia na qual estão localizados. Mover um controle de uma guia para outra em uma nova versão do formulário pode quebrar as personalizações que o usuário faz para esse controle, porque as personalizações não conseguirão identificar o controle de destino.

  • Quando a atualização de um formulário incluir novos controles, considere adicionar os novos controles a uma nova guia. Essa é a maneira mais segura de evitar interferir com quaisquer personalizações do usuário para as guias e controles existentes.

  • Esteja ciente de como os controles são vinculados. Os controlos somente de leitura devem usar apenas vinculações unidirecionais.

Nomeie todos os controles personalizáveis

Certifique-se de que os nomes de controle descrevam a quais dados o controle está vinculado ou descrevam o que o controle faz.

Vincular o formulário a fontes de dados

O objetivo principal de um formulário é visualizar um único objeto do banco de dados do Service Manager. Esse objeto é chamado de instância de destino, que é sempre especificada pela propriedade DataContext de um formulário (que é herdada da classe FrameworkElement).

Importante

Não modifique a propriedade DataContext do formulário. O ambiente de hospedagem de formulários usa essa propriedade para identificar a instância de destino do formulário.

No modelo de dados do Service Manager, uma instância de destino é representada como um objeto BindableDataItem. Essa classe agrega o objeto subjacente do kit de desenvolvimento de software (SDK) e expõe suas propriedades por meio de um indexador, que usa um nome de propriedade como parâmetro.

A classe BindableDataItem também implementa ICustomTypeDescriptor, o que torna possível usar a classe BindableDataItem como uma fonte de dados para ligação WPF. A seguir está um exemplo de vinculação de uma propriedade de instância de destino à propriedade Text de um controle TextBox:


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

Não é necessário especificar o de origem da associação porque as instâncias de destino são definidas como o DataContext do formulário, que serve como o de origem padrão para todos os controles no formulário.

Os controles no formulário podem ser vinculados a fontes de dados diferentes da instância de destino, e a biblioteca de infraestrutura de formulários contém muitos controles que executam a associação implicitamente. Por exemplo, o controle do seletor de instâncias é vinculado à fonte de dados, que fornece a coleção de instâncias a serem escolhidas. Também é possível definir fontes de dados adicionais declarativamente usando as classes ObjectDataProvider e XmlDataProvider.

A infraestrutura de formulários considera a instância de destino como a única fonte de dados de leitura/gravação no formulário. Portanto, a implementação do comando Submit armazenará apenas as alterações feitas na instância de destino. Outras fontes de dados para o formulário são consideradas como somente leitura.

Utilize regras de validação da infraestrutura de formulários do Service Manager, conversores de valor e modelos de erro.

Recomendamos que você use regras de validação de infraestrutura de formulários em formulários para designar a entrada de dados que não é válida. A infraestrutura de vinculação do WPF oferece suporte à validação de propriedades de controle que estão vinculadas a uma fonte de dados com ligações unidirecionais ou bidirecionais. O objeto de ligação tem uma coleção ValidationRules que pode conter qualquer número de objetos ValidationRule. Sempre que os dados são transferidos do controlo para a origem de dados, os objetos ValidationRule são chamados para validar os valores.

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 do formulário pode ser enviado para armazenamento. Por exemplo, o botão Enviar de um formulário pode ser desativado se houver um controle que tenha um erro de validação no formulário.

Recomendamos que você use o modelo de erro personalizado fornecido com a biblioteca de infraestrutura de formulários. Se um controle tiver um erro de validação, ele aparecerá por padrão com uma borda vermelha ao redor. O WPF torna possível definir um indicador de erro personalizado através da propriedade Validation.ErrorTemplate, que pode ser definida em qualquer controle. A biblioteca de infraestrutura de formulários do Service Manager contém um modelo de erro personalizado, que exibe um ícone de erro em vez da borda vermelha do WPF. Além disso, quando o rato paira sobre o ícone de erro, uma dica de ferramenta aparece com uma mensagem de erro. A mensagem de erro deve indicar o motivo pelo qual os dados no controle falharam na validação.

O exemplo a seguir 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 internas não fornecerem a lógica de validação necessária, recomendamos que você crie regras de validação personalizadas para representar essa lógica. Tal permitirá a coexistência de lógicas de validação normalizadas e personalizadas no âmbito do mecanismo comum de tratamento da validação.

Se o mecanismo de regras de validação não for adequado para um cenário específico, você deverá manipular FormEvents.PreviewSubmitEvent e executar a validação a partir daí.

O exemplo de código a seguir fornece um exemplo do padrão que você pode usar para executar a 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
}

Usar comandos e eventos da infraestrutura de formulário

A infraestrutura de formulário expõe muitos comandos que podem ser executados em um formulário. Esses comandos incluem:

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

  • FormsCommand.SubmitAndClose, que salva 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 descarta todas as alterações e fecha o formulário.

Cada um desses comandos é colocado entre colchetes por eventos, que são gerados antes e depois da execução do comando.

Antes do comando, os seguintes eventos são gerados:

  • O evento FormEvents.PreviewSubmit é gerado antes do comando FormCommand.Submit e o evento FormEvents.Submitted é 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 um objeto PreviewFormCommandEventArgs. Este objeto contém uma propriedade mutável Cancel que impedirá que o comando correspondente seja executado quando a propriedade estiver definida como true.

Os eventos pós-comando passam um objeto FormCommandExecutedEventArgs. Este objeto contém uma propriedade Result que indica se a execução do comando foi bem-sucedida, foi cancelada ou causou um erro. Em caso de erro, a propriedade Error do objeto FormCommandExecutedEventArgs faz referência à 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 habilitar comandos de formulário programaticamente, estabeleça um CommandBinding () entre o formulário e o comando relacionado.

No exemplo a seguir, uma ligação de comando é estabelecida entre o formulário e um comando Refresh, e dois manipuladores são definidos para esse comando. O primeiro manipulador retorna se o comando Refresh pode ou não ser executado, e o segundo manipulador realmente contém a implementação do comando Refresh:


    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
        }
    }

Você também pode definir manipuladores para comandos de formulário declarativamente. Você pode fazer isso empregando um objeto Rule que usa um RoutedCommandTrigger. O exemplo de código a seguir mostra como definir manipuladores declarativamente:


    <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>

Próximos passos