Información general sobre la personalización y creación de formularios con la herramienta de creación de Service Manager

Importante

Esta versión de Service Manager ha llegado al final del soporte técnico. Se recomienda actualizar a Service Manager 2022.

Un formulario es una ventana que permite a los usuarios interactuar con objetos de la base de datos. Los usuarios pueden utilizar los formularios para ver y editar las propiedades de los objetos. Cada formulario está enlazado a una clase concreta y muestra únicamente la información de las instancias de la clase de destino. Los formularios contienen campos. Normalmente, cada campo está enlazado a una propiedad específica de la clase de destino del formulario. Por ejemplo, el formulario de incidente está enlazado al objeto incidente. Por lo tanto, el formulario de incidente muestra información acerca de los objetos de incidentes de la base de datos.

Un formulario de Service Manager consta de la implementación del formulario de Windows Presentation Foundation (WPF) en un ensamblado de Microsoft .NET Framework y una definición de formulario en un módulo de administración de Service Manager. La definición del formulario especifica la clase que representa el formulario, junto con las restantes propiedades del formulario.

Conceptos clave sobre los formularios

Para poder personalizar formularios, debe estar familiarizado con los siguientes conceptos de formulario.

Cómo se usan los formularios

Cuando el módulo de administración que contiene las definiciones de formulario se importa en Service Manager, las definiciones de formulario se almacenan en la base de datos. Más adelante, cuando el usuario inicia una tarea de consola de Service Manager que requiere la presentación de un objeto, Service Manager debe encontrar un formulario para mostrar el objeto solicitado. Service Manager accede a la base de datos y busca un formulario definido para ese objeto. Si no se define ningún formulario para el objeto, Service Manager busca un formulario definido para el objeto primario del objeto. Service Manager continúa buscando en la jerarquía de herencia del objeto completo hasta que encuentre un formulario definido.

Formularios genéricos

Si Service Manager no encuentra ningún formulario para el objeto o para cualquiera de sus objetos primarios, Service Manager crea dinámicamente un formulario genérico predeterminado para ese objeto. El formulario genérico es un formulario generado por el sistema, suficiente para el uso de un formulario simple. El formulario genérico representa una forma rápida y fácil para crear un formulario para objetos sin definiciones de formulario.

De forma predeterminada, el formulario genérico muestra todas las propiedades del formulario en un diseño simple que no se puede cambiar. El formulario genérico muestra las propiedades de todos los objetos primarios de la jerarquía de herencia del formulario y no puede cambiar ese comportamiento. Las personalizaciones en el formulario genérico están limitadas. Por ejemplo, puede especificar las propiedades que desea que se muestre el formulario genérico; Sin embargo, el formulario genérico no se puede usar como base para la personalización. Si más adelante define un formulario personalizado para ese objeto, el formulario personalizado sobrescribe el formulario genérico del objeto.

Para obtener información sobre la ocultación de propiedades en un formulario genérico y otras formas de personalización de un formulario genérico, consulte la entrada de blog Overview of the Forms Infrastructure and the Generic Form (Introducción a la infraestructura de formularios y al formulario genérico).

Clases combinadas en formularios

En ocasiones, es necesario que un formulario muestre la información que se deriva de más de una clase. Para ello, cree una clase de combinación y, a continuación, enlace un campo del formulario a la clase de combinación. Para obtener más información sobre las clases de combinación, consulte Cambios en el esquema común de System Center.

Aspectos funcionales de un formulario

Un formulario tiene los siguientes aspectos funcionales:

  1. Inicialización

  2. Tamaño y ubicación

  3. Actualizar

  4. Enviar cambios

Estos aspectos se describen en las secciones siguientes.

Inicialización

Durante la inicialización, se analiza el Lenguaje de marcado extensible de aplicación (XAML) de un formulario y se crean instancias y se cargan todos los controles del formulario. El evento Loaded del formulario indica cuándo se ha cargado el formulario y todos los elementos contenidos. Las operaciones de carga de datos son asincrónicas. Por lo tanto, es posible que la instancia de destino no esté disponible cuando se produzca el evento Loaded . En su lugar, utilice el evento DataContextChanged para la notificación si la instancia de destino está establecida para el formulario. Puede utilizar el evento PropertyChanged para la propiedad DataContext en lugar del evento DataContextChanged .

Es recomendable utilizar el evento Loaded para la inicialización personalizada relacionada con el control y después usar los eventos DataContextChanged o PropertyChanged de la propiedad DataContext para la inicialización personalizada relacionada con la instancia de destino.

Tamaño y ubicación

Cuando se muestra un formulario en una ventana emergente, su tamaño inicial se determina en función de las propiedades Width, Height, MinWidth y MinHeight del formulario. Si estas propiedades no se establecen para el formulario, el tamaño inicial del formulario se calcula en función de su contenido.

Es recomendable establecer estas propiedades de la forma siguiente:

  • Establezca las propiedades Width y Height del formulario para especificar explícitamente el tamaño ideal. Considere la posibilidad de establecer estas propiedades en el valor Auto . Así se establece el ancho y el alto del formulario en función del tamaño del contenido.

  • Establezca las propiedades MinWidth y MinHeight del formulario para especificar la ventana más pequeña aceptable para el formulario. Si un usuario cambia el tamaño de la ventana por un tamaño inferior al especificado, aparecen barras de desplazamiento para desplazarse hasta el contenido oculto del formulario.

Cuando el formulario se hospeda dentro del host de formularios de Service Manager, el tamaño y la ubicación usados se conservan para la presentación posterior de ese formulario por el mismo usuario dentro de la misma sesión de ejecución.

Actualizar

La instancia de destino de un formulario puede cambiar como resultado de ejecutar un comando Refresh en el formulario. El controlador para este comando captura los datos nuevos de la base de datos. Cuando llegan los datos, el valor de la propiedad DataContext del formulario se establece en la nueva instancia de destino y se genera el evento DataContextChanged .

Para diferenciar entre el evento DataContextChanged , que se produjo la primera vez que se cargó el formulario, y el evento que se produjo para controlar un comando Refresh , compruebe la propiedad OldValue de los argumentos del evento que se pasan con el mismo. Esta propiedad es nula si se acaba de inicializar el formulario.

Enviar cambios

La ventana emergente del host de formulario en Service Manager proporciona botones para enviar los cambios realizados en el formulario y para cerrar la ventana emergente.

Cuando un usuario selecciona el botón Aplicar para un formulario, se envía la instancia de destino del formulario para el almacenamiento. Esta operación es sincrónica; por lo tanto, el usuario no puede editar el formulario hasta que se complete la operación de envío. Si se produce un error durante el envío del formulario, aparece un mensaje de error. El formulario permanece abierto para futuras modificaciones. Es recomendable que los usuarios apliquen sus cambios con frecuencia para evitar colisiones si se está editando otra instancia del formulario al mismo tiempo.

Si el usuario selecciona el botón Aceptar , el comportamiento es similar a Aplicar, salvo que, si la operación de envío del formulario se realiza correctamente, se cierra el formulario y su ventana host.

Si el usuario selecciona el botón Cancelar , aparece un cuadro de diálogo que pide al usuario que confirme la operación. El usuario puede seleccionar y perder cambios, o bien seleccionar No y volver al formulario.

Directrices generales y procedimientos recomendados para formularios

Puede ampliar las características de Service Manager agregando o modificando formularios. En esta sección se describen algunas recomendaciones de procedimientos recomendados para crear y usar formularios Service Manager, mediante varias herramientas y definiciones de formularios de scripting directamente.

Esta sección está dirigida principalmente a asociados y clientes que tienen experiencia en la creación de sus propios formularios personalizados mediante Windows Presentation Foundation (WPF) y Microsoft Visual Studio Team System o Microsoft Expression Blend.

Las instrucciones generales para la creación de un nuevo formulario son las siguientes.

  • Utilizar controles estándar.
  • Seguir las instrucciones generales de diseño de formularios.
  • Evitar el código subyacente.
  • Incluir el control de excepciones.
  • Tomar en consideración las actualizaciones y personalizaciones de formularios.
  • Asignar un nombre a todos los controles personalizables.
  • Enlazar el formulario a los orígenes de datos.
  • Use Service Manager formularios reglas de validación de infraestructura, convertores de valor y plantillas de error.
  • Utilizar los comandos y eventos de infraestructura de formularios.

Para obtener información acerca de estas instrucciones, consulte las secciones siguientes.

Uso de controles estándar

Entre los controles que se utilizan en un formulario se incluyen:

  • Controles estándar. Entre ellos se incluyen los controles de la biblioteca. NET, como el cuadro combinado y el cuadro de lista.
  • Controles personalizados. Entre ellos se incluyen los controles adicionales creados por el autor del formulario o por un tercero.

Sugerencia

Si utiliza controles estándar siempre que es posible y evita la creación de controles personalizados, estará contribuyendo a la consistencia de la experiencia del usuario en relación con el uso de formularios. Si tiene que crear un control personalizado, separe el comportamiento y la apariencia visual del comportamiento lógico mediante el uso de plantillas de control para definir la apariencia del control. Preferiblemente, debería haber una plantilla de control independiente para cada tema de Windows.

Siga las instrucciones generales de diseño de formularios

A la hora de diseñar un formulario, utilice las instrucciones de diseño de acceso público, para asegurarse de que el formulario es descriptivo y que se adhiere a los paradigmas comunes de interacción del usuario.

Para obtener más información acerca del diseño general de Windows, consulte Windows User Experience Interaction Guidelines (Instrucciones de interacción de Windows User Experience).

Además:

  • Divida la información entre varias pestañas para que el formulario sea más sencillo y fácil de leer. Incluya la información más usada en la primera pestaña e información de menor importancia en las pestañas posteriores.
  • Utilice los paneles de diseño para colocar controles en el formulario. Esto garantiza que el formulario se comporte correctamente cuando se cambia de tamaño y se localiza.
  • Evite establecer propiedades visuales de control individual y utilice estilos en su lugar. Esto permite cambiar la apariencia de todos los controles de una serie de formularios modificando el estilo y promueve una apariencia coherente entre los formularios relacionados.

Evitar código subyacente

Código subyacente es un término que describe el código que se une con objetos definidos por marcado cuando se compila una página XAML mediante marcado. Limite lo máximo posible el uso de código subyacente en un formulario. Es preferible insertar el código para un formulario en el propio control, ya que más adelante es más fácil cambiar ese código. En su lugar, use las funcionalidades declarativas admitidas por la infraestructura de formularios de Service Manager para definir conversiones de valores y reglas de validación en el formulario.

Como guía general, debes limitar el uso de código subyacente a situaciones en las que no es posible proporcionar la funcionalidad necesaria mediante las funcionalidades declarativas de XAML, con clases definidas en WPF y la biblioteca de infraestructura de formularios. Aún así, considere la posibilidad de mover la funcionalidad que se implementa en código subyacente a una biblioteca del asistente y, a continuación, haga referencia a ella desde XAML.

Incluir el control de excepciones

Asegúrese de que el código del formulario contiene el control de excepciones para que el formulario se pueda cargar durante la fase de diseño de la herramienta de creación y en la consola de Service Manager en tiempo de ejecución.

Considerar la personalización y las actualizaciones de formularios

Al diseñar un nuevo formulario, debe considerar las futuras personalizaciones y actualizaciones de ese formulario. Para asegurarse de que es posible personalizar y actualizar un formulario a la vez que conserva las personalizaciones, siga las instrucciones y sugerencias que se proporcionan anteriormente en esta sección, junto con las siguientes directrices:

  • Considere las futuras personalizaciones y actualizaciones al principio mientras diseña el formulario. Es probable que los formularios evolucionen en versiones futuras y es importante tener en cuenta cómo los usuarios podrán actualizar a las nuevas versiones del formulario a la vez que conservan sus personalizaciones en el formulario original. Por ejemplo, podría proporcionar un formulario actualizado después de que los usuarios hayan hecho un gran esfuerzo en la personalización del formulario original. Los usuarios esperan que sus personalizaciones sobrevivan a la actualización de versión.

  • Asigne un nombre único a cada control del formulario para que las personalizaciones se puedan aplicar a los controles. Las personalizaciones de formularios se almacenan como un conjunto de acciones destinadas a un control específico o a un conjunto de controles. El control de destino se hace referencia por nombre, por lo que es importante conservar los nombres de control entre versiones del formulario. Si un control no tiene un nombre, la personalización de formularios Editor genera un nombre, pero el nombre generado no se conserva en distintas versiones del formulario.

  • Asegúrese de que los nombres de control permanecen inmutables en distintas versiones del formulario. De esta forma se garantiza que las personalizaciones de un control determinado en una versión anterior se pueden aplicar al mismo control en una nueva versión del formulario.

  • Si es posible, evite mover controles a una ubicación diferente en la misma pestaña cuando actualice un formulario. Una personalización común de usuario desplaza los controles del formulario a una ubicación diferente. Si cambia la ubicación de un control en una nueva versión del formulario, existe el riesgo de que la nueva ubicación del control se superponga con un control que el usuario ha reubicado.

  • Si es posible, evite mover controles entre pestañas al diseñar una actualización a un formulario existente. Los controles se identifican por nombre y por la pestaña en la que se encuentran. Si mueve un control de una pestaña a otra en una nueva versión del formulario puede interrumpir las personalizaciones que el usuario haga en dicho control, ya que en las personalizaciones se producirá un error de identificación del control de destino.

  • Cuando la actualización a un formulario incluya nuevos controles, considere la posibilidad de agregar los nuevos controles a una nueva pestaña. Esa es la manera más segura de evitar interferir con las personalizaciones de usuario en las pestañas y controles existentes.

  • Tenga en cuenta cómo se enlazan los controles. Los controles de solo lectura deben utilizar únicamente enlaces unidireccionales.

Asignar un nombre a todos los controles personalizables

Asegúrese de que los nombres de los controles describen los datos a los que está enlazados o lo que dichos controles hacen.

Enlace del formulario a orígenes de datos

El propósito principal de un formulario es visualizar un único objeto de la base de datos Service Manager. Este objeto se denomina target instancey siempre se especifica mediante la propiedad DataContext de un formulario (que se hereda de la clase FrameworkElement ).

Importante

No modifique la propiedad DataContext del formulario. El entorno de hospedaje de los formularios utiliza esta propiedad para identificar la instancia de destino del formulario.

En el modelo de datos Service Manager, una instancia de destino se representa como un objeto BindableDataItem. Esta clase agrega el objeto subyacente del kit de desarrollo de software (SDK) y expone sus propiedades a través de un indizador, que toma como parámetro un nombre de propiedad.

La clase BindableDataItem también implementa ICustomTypeDescriptor, lo que hace posible el uso de la clase BindableDataItem como origen de datos para el enlace de WPF. El siguiente es un ejemplo de enlace de una propiedad de instancia de destino a la propiedad Text de un control TextBox :


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

No es necesario especificar el origen del enlace porque las instancias de destino se establecen como DataContext del formulario, que actúa como origen predeterminado para todos los controles del formulario.

Los controles del formulario se pueden enlazar a orígenes de datos distintos de la instancia de destino y la biblioteca de infraestructura de formularios contiene muchos controles que realizan el enlace implícitamente. Por ejemplo, el control del selector de instancia está enlazado al origen de datos, lo que proporciona la recopilación de instancias para elegir. También es posible definir orígenes de datos adicionales mediante declaración mediante las clases ObjectDataProvider y XmlDataProvider .

La infraestructura de formularios considera la instancia de destino como el origen único de los datos de solo lectura y escritura en el formulario. Por lo tanto, la implementación del comando Submit solo guardará los cambios realizados en la instancia de destino. El resto de los orígenes de datos para el formulario se tratan como de solo lectura.

Usar Service Manager formularios reglas de validación de infraestructura, convertidores de valores y plantillas de error

Se recomienda usar reglas de validación de infraestructura de formularios en formularios para designar la entrada de datos que no es válida. La infraestructura de enlace de WPF admite la validación de las propiedades de control que están enlazadas a un origen de datos mediante enlaces unidireccionales o bidireccionales. El objeto de enlace tiene una colección ValidationRules que puede contener cualquier número de objetos ValidationRule . Cada vez que los datos se insertan desde el control al origen de datos, se llama a los objetos ValidationRule para validar el valor.

La biblioteca de infraestructura de formularios contiene muchas reglas de validación que controlan los casos más comunes. La infraestructura de formularios aprovecha las ventajas de las reglas de validación para determinar si el contenido de los formularios se puede enviar para almacenar. Por ejemplo, el botón Enviar de un formulario se puede deshabilitar si hay un control que tiene un error de validación en el formulario.

Es recomendable utilizar la plantilla personalizada de errores que se proporciona con la biblioteca de infraestructura de formularios. Si un control tiene un error de validación, aparece de forma predeterminada con un borde rojo alrededor del mismo. WPF permite definir un indicador personalizado de errores mediante la propiedad Validation.ErrorTemplate , que se puede establecer en cualquier control. La biblioteca de infraestructura de formularios Service Manager contiene una plantilla de error personalizada, que muestra un icono de error en lugar del borde rojo de WPF. Además, al señalar el icono de error con el mouse, aparece una información sobre herramientas con un mensaje de error. El mensaje de error debe indicar el motivo por el cual no se han podido validar los datos en el control.

En el ejemplo siguiente se muestra cómo hacer referencia a la plantilla de errores en XAML:


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

Si las reglas de validación integradas no proporcionan la lógica de validación necesaria, se recomienda crear reglas de validación personalizadas para representar esa lógica. De esta forma, las lógicas de validación estándar y personalizada pueden coexistir en el mecanismo común de control de validaciones.

Si el mecanismo de reglas de validación no es adecuado para un escenario determinado, en su lugar debe controlar FormEvents.PreviewSubmitEvent y ejecutar la validación desde allí.

El siguiente código de muestra proporciona un ejemplo del patrón que puede utilizar para ejecutar la validación 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
}

Uso de eventos y comandos de infraestructura de formularios

La infraestructura del formulario expone muchos comandos que se pueden ejecutar en un formulario. Entre estos comandos se incluyen:

  • FormsCommand.Submit, que guarda la instancia de destino del formulario.

  • FormsCommand.SubmitAndClose, que guarda la instancia de destino del formulario y cierra el formulario.

  • FormsCommand.Refresh, que repite la consulta para la instancia de destino del formulario.

  • FormCommands.Cancel, que descarta todos los cambios y cierra el formulario.

Los eventos, que se producen antes y después de la ejecución de los comandos, muestran cada comando entre corchetes.

Antes del comando se producen los eventos siguientes:

  • El evento FormEvents.PreviewSubmit se produce antes del comando FormCommand.Submit y el evento FormEvents.Submitted se produce después del comando FormCommand.Submit .

  • El evento FormEvents.PreviewRefresh se produce antes del comando FormCommands.Refresh y el comando FormCommand.Refreshed se produce después del comando FormCommand.Submit .

  • El evento FormEvents.PreviewCancel se produce antes del comando FormCommands.Cancel y el evento FormCommand.Canceled se produce después del comando FormCommand.Cancel .

La vista preliminar de los eventos pasa un objeto PreviewFormCommandEventArgs . Este objeto contiene una propiedad Cancel mutable, que impedirá la ejecución del comando correspondiente si la propiedad está establecida en true.

Los eventos posteriores a los comandos pasan un objeto FormCommandExecutedEventArgs . Este objeto contiene una propiedad Result , que indica si la ejecución del comando se ha realizado con éxito, se ha cancelado o ha producido un error. En caso de error, la propiedad Error del objeto FormCommandExecutedEventArgs hace referencia a la excepción que proporciona información sobre el error.

Es posible habilitar, deshabilitar y ejecutar comandos de formulario mediante programación y mediante declaración.

Para habilitar comandos de formulario mediante programación, establezca un CommandBinding entre el formulario y el comando relacionado.

En el siguiente ejemplo, se establece un enlace de comando entre el formulario y un comando Refresh y se definen dos controladores para este comando. El primer controlador indica si el comando Refresh se puede ejecutar o no y el segundo controlador contiene la implementación del 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
        }
    }

También puede definir controladores para comandos de formulario mediante declaración. Para ello, utilice un objeto Regla que usa un RoutedCommandTrigger. En el ejemplo de código siguiente se muestra cómo definir controladores mediante declaración:


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

Pasos siguientes