Tutorial: Crear una extensión de tipo de negocios

En este tutorial se muestra cómo crear una extensión de tipo empresarial para Visual Studio LightSwitch. Crear una extensión de tipo empresarial en LightSwitch permite presentar datos de la manera más adecuada para la aplicación sin cambiar el tipo de datos en que se almacenan en la base de datos subyacente. Por ejemplo, puede almacenar valores en el tipo de datos Decimal en la base de datos, pero usar el tipo empresarial Money integrado para mostrar esos valores en formato Currency en la pantalla y proporcionar un control de valor para mostrar, editar y validar la divisa.

Para cada extensión de tipo empresarial, debe realizar las siguientes tareas:

  • Crear un proyecto de extensión.

  • Especificar el tipo de datos que se va a invalidar.

Las siguientes tareas son opcionales:

  • Probar la extensión de tipo empresarial.

  • Definir un control correspondiente para el tipo empresarial.

  • Definir la validación del tipo empresarial.

  • Agregar una propiedad personalizada al tipo empresarial.

  • Compilar un editor de propiedades para las propiedades de tipo empresarial.

Requisitos previos

  • Visual Studio 2013 Professional

  • Visual Studio 2013 SDK

  • LightSwitch Extensibility Toolkit para Visual Studio 2013

Crear un proyecto de extensión de tipo empresarial

El primer paso es crear un proyecto y agregar una plantilla de tipo empresarial de LightSwitch.

Para crear un proyecto de extensión

  1. En la barra de menús de Visual Studio, elija Archivo, Nuevo, Proyecto.

  2. En el cuadro de diálogo Nuevo proyecto, expanda el nodo Visual Basic o el nodo Visual C#, expanda el nodo LightSwitch, elija el nodo Extensibilidad y, a continuación, elija la plantilla Biblioteca de extensión de LightSwitch.

  3. En campo Nombre, escriba BusinessTypeExtension como nombre de la biblioteca de extensiones. Este nombre aparecerá en la pestaña Extensiones del Diseñador de aplicaciones de LightSwitch.

  4. Elija el botón Aceptar para crear una solución que contenga los siete proyectos que son necesarios para la extensión.

Para elegir un tipo de extensión

  1. En el Explorador de soluciones, elija el proyecto BusinessTypeExtension.Lspkg.

  2. En la barra de menús, elija Proyecto, Agregar nuevo elemento.

  3. En el cuadro de diálogo Agregar nuevo elemento, elija Tipo empresarial.

  4. En campo Nombre, escriba PositiveInteger como nombre de la extensión. Este nombre aparecerá en el Diseñador de pantallas de LightSwitch.

  5. Elija el botón Aceptar. Los archivos se agregarán a varios proyectos de la solución.

Especificar el tipo de datos que se va a invalidar

Un tipo empresarial invalida un tipo de datos base, proporcionando un formato y una validación personalizados. Debe actualizar los metadatos para que el tipo empresarial refleje el tipo subyacente que se va a invalidar. Además de los tipos de datos base, también puede invalidar otros tipos empresariales. Para obtener una lista de los tipos de datos admitidos que puede que desee invalidar, consulte Tipos de datos compatibles para extensiones de LightSwitch.

Para especificar el tipo

  1. En el Explorador de soluciones, elija el proyecto BusinessTypeExtension.Common.

  2. Expanda los nodos Metadatos y Tipos, abra el menú contextual del archivo PositiveInteger.lsml y elija Abrir con.

  3. En el cuadro de diálogo Abrir con, elija Editor XML (texto) y, a continuación, elija el botón Aceptar.

  4. En el elemento SemanticType, reemplace el valor UnderlyingType por Int32 y el valor DisplayName por Positive Integer, como sigue.

    <SemanticType Name="PositiveInteger"
        UnderlyingType=":Int32">
        <SemanticType.Attributes>
          <DisplayName Value="Positive Integer" />
        </SemanticType.Attributes>
      </SemanticType>
    

    El valor UnderlyingType indica a LightSwitch que los datos para el tipo deben almacenarse como tipo de datos Int32 en la base de datos. Los tipos de datos deben especificarse en un archivo .lsml usando el nombre de modulo y el nombre del tipo de datos. La notación ”:” es un acceso directo a “Microsoft.LightSwitch:”. El valor DisplayName aparecerá en la lista Tipo del Diseñador de tablas. Por consiguiente, es conveniente proporcionar un nombre descriptivo.

En este punto, se ha creado un tipo empresarial y puede probarlo en una aplicación de LightSwitch.

Probar la extensión de tipo empresarial

Puede probar la extensión de tipo empresarial en una instancia experimental de Visual Studio. Si todavía no ha probado ningún proyecto de extensibilidad LightSwitch, primero tiene que habilitar la instancia experimental.

Para habilitar una instancia experimental

  1. En el Explorador de soluciones, elija el proyecto BusinessTypeExtension.Vsix.

  2. En la barra de menús, elija Proyecto, Propiedades de BusinessTypeExtension.Vsix.

  3. En la pestaña Depurar, en Acción de inicio, elija Programa externo de inicio.

  4. Escriba la ruta del archivo ejecutable de Visual Studio, devenv.exe.

    De forma predeterminada en un sistema de 32 bits la ruta de acceso es C:\Archivos de programa\Microsoft Visual Studio 12.0\Common7\IDE\devenv.exe; en un sistema de 64 bits, es C:\Archivos de programa (x86)\Microsoft Visual Studio 12.0\Common7\IDE\devenv.exe.

  5. En el campo Argumentos de la línea de comandos, escriba /rootsuffix Exp.

    Nota

    De forma predeterminada, todos los proyectos de extensibilidad de LightSwitch subsiguientes también usarán este valor.

Para probar el tipo empresarial

  1. En la barra de menús, elija Depurar, Iniciar depuración. Se abre una instancia experimental de Visual Studio.

  2. En la instancia experimental, en la barra de menús, elija Archivo, Nuevo, Proyecto.

  3. En el cuadro de diálogo Nuevo proyecto, expanda el nodo Visual Basic o Visual C#, elija el nodo LightSwitch y después elija la plantilla Aplicación de escritorio de LightSwitch.

  4. En el campo Nombre, escriba BusinessTypeTest y elija el botón Aceptar para crear un proyecto de prueba.

  5. En el Explorador de soluciones, elija el proyecto BusinessTypeTest.

  6. En la barra de menús, elija Proyecto, Propiedades de BusinessTypeTest.

  7. En el Diseñador de proyectos, en la pestaña Extensiones, active la casilla BusinessTypeExtension.

  8. Agregue una tabla con un campo Nombre de tipo String y un campo Puntuación de tipo Positive Integer.

  9. Agregue una Pantalla de lista y detalles con la tabla como origen de Datos de pantalla y, en el Diseñador de pantallas, observe que el control del campo Score es Control PositiveInteger.

  10. En la barra de menús, elija Depurar, Iniciar depuración. Para observar el comportamiento del Control PositiveInteger en la aplicación, agregue algunos datos.

Es posible que haya observado que el Control PositiveInteger es de tipo TextBox que solo acepta datos numéricos. El comportamiento es igual que para un tipo de datos ShortInteger. Para hacer que el tipo empresarial Positive Integer sea más útil, puede realizar una o varias de las tareas opcionales para crear una extensión de tipo empresarial. Estas tareas se cubren en el resto del tutorial.

Definir un control correspondiente

Cuando se crea una extensión de tipo empresarial, también se crea un control de LightSwitch correspondiente. De forma predeterminada, un control TextBox simple se define en lenguaje XAML; puede modificar o reemplazar el código XAML para crear un control personalizado para el tipo empresarial.

Cualquier control que se pueda usar para el tipo base también se podrá usar para el tipo empresarial. Por consiguiente, el control incluido no se requiere a menos que desee cambiar el comportamiento o la interfaz de usuario.

También puede definir varios controles para un tipo empresarial. Para obtener más información, vea Cómo: Crear varios controles para un tipo de negocios.

Para reemplazar el control predeterminado

  1. En el Explorador de soluciones, elija las carpetas Presentation y Controls del proyecto BusinessTypeExtension.Client y abra el archivo PositiveIntegerControl.xaml.

  2. Reemplace el elemento <TextBox Text="{Binding StringValue, Mode=TwoWay}"/> por el código XAML siguiente.

    <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
    
            <Slider Value="{Binding Details.Value, Mode=TwoWay}" Minimum="-100" Maximum="100" SmallChange="1" LargeChange="5"/>
            <TextBlock Grid.Column="1" Text="{Binding Value}" MinWidth="30"/>
        </Grid>
    

    El código muestra cómo reemplazar el control TextBox predeterminado por un control Slider dentro de un diseño Grid. Establece los valores Minimum y Maximum fijos para el control deslizante y también agrega un control TextBlock para mostrar el valor actual.

En este punto, puede probar el comportamiento de nuevo en la instancia experimental. Al ejecutar el proyecto BusinessTypeTest, puede ver que el control TextBox se ha reemplazado por Slider y que el valor se muestra en un TextBlock.

Definir la validación del tipo empresarial

En la mayoría de los casos, puede que desee agregar validación integrada para el tipo empresarial. Para agregar esta funcionalidad, debe agregar una regla de validación para el tipo. Puede administrar fácilmente los datos del control integrado. Sin embargo, puede que un desarrollador desee usar un control diferente para mostrar el tipo empresarial. Para exigir la validación cuando el tipo empresarial se usa con cualquier tipo de control, debe implementar la validación tanto en el servidor como en el cliente. Solo una regla de validación puede satisfacer esas necesidades.

Antes de agregar una regla de validación, debe agregar una clase estática a fin de definir algunos nombres de constantes para el tipo de datos y el control. Esos nombres se usarán posteriormente en las reglas de validación.

Para definir constantes

  1. En el Explorador de soluciones, elija el proyecto BusinessTypeExtension.Common.

  2. En el menú Proyecto, elija Agregar clase.

  3. En el cuadro de diálogo Agregar nuevo elemento, elija el campo Nombre, escriba BusinessTypeExtensionModule y, a continuación, elija el botón Agregar.

  4. En el archivo BusinessTypeExtensionModule, reemplace el contenido existente por el siguiente código:

    Friend Module BusinessTypeExtensionModule
    
        Private Const Name As String = "BusinessTypeExtension"
        Private Const ModulePrefix As String = Name + ":"
        Private Const AttributePrefix As String = ModulePrefix + "@"
    
        Friend Class PositiveInteger
    
            Private Const Name As String = "PositiveInteger"
            Public Const GlobalName As String = ModulePrefix + Name
    
            Friend Class ValidationAttribute
    
                Private Const Name As String = "PositiveIntegerValidation"
                Public Const GlobalName As String = AttributePrefix + Name
            End Class
    
        End Class
    
    End Module
    
    namespace BusinessTypeExtension
    {
        internal static class BusinessTypeExtensionModule
        {
            private const string Name = "BusinessTypeExtension";
            private const string ModulePrefix = Name + ":";
            private const string AttributePrefix = ModulePrefix + "@";
    
            internal static class PositiveInteger
            {
                private const string Name = "PositiveInteger";
                public const string GlobalName = ModulePrefix + Name;
    
                internal static class ValidationAttribute
                {
                    private const string Name = "PositiveIntegerValidation";
                    public const string GlobalName = AttributePrefix + Name;
                }
            }
        }
    }
    

El paso siguiente consiste en agregar reglas de validación. El código de validación que se agregue al proyecto Common se cargará tanto en el servidor como en el cliente de LightSwitch. Esta acción garantiza la aplicación de la misma lógica en ambas capas.

Para agregar una regla de validación

  1. En el Explorador de soluciones, elija el proyecto BusinessTypeExtension.Common.

  2. En el menú Proyecto, elija Agregar clase.

  3. En el cuadro de diálogo Agregar nuevo elemento, elija el campo Nombre, escriba PositiveIntegerValidation y, a continuación, elija el botón Agregar.

  4. En el archivo PositiveIntegerValidation reemplace el contenido existente por el siguiente código.

    Imports System
    Imports System.Collections.Generic
    Imports System.ComponentModel.Composition
    Imports System.Linq
    Imports Microsoft.LightSwitch
    Imports Microsoft.LightSwitch.Model
    Imports Microsoft.LightSwitch.Runtime.Rules
    
    Public Class PositiveIntegerValidation
        Implements IAttachedPropertyValidation
    
        Public Sub New(attributes As IEnumerable(Of IAttribute))
            Me.attributes = attributes
        End Sub
    
        Private attributes As IEnumerable(Of IAttribute)
    
        Public Sub Validate(value As Object, results As IPropertyValidationResultsBuilder) Implements Microsoft.LightSwitch.Runtime.Rules.IAttachedPropertyValidation.Validate
            If value IsNot Nothing Then
    
                ' Ensure the value type is integer.
                If GetType(Integer) IsNot value.GetType() Then
                    Throw New InvalidOperationException("Unsupported data type.")
                End If
    
                Dim intValue As Integer = DirectCast(value, Integer)
    
                ' First validation rule: value should be greater than 0.
                If intValue <= 0 Then
                    results.AddPropertyError("Value should be greater than 0")
                End If
    
            End If
        End Sub
    
    End Class
    
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.Composition;
    using System.Linq;
    using Microsoft.LightSwitch;
    using Microsoft.LightSwitch.Model;
    using Microsoft.LightSwitch.Runtime.Rules;
    
    namespace BusinessTypeExtension
    {
        public class PositiveIntegerValidation : IAttachedPropertyValidation
        {
            public PositiveIntegerValidation(IEnumerable<IAttribute> attributes)
            {
                _attributes = attributes;
            }
    
            private IEnumerable<IAttribute> _attributes;
    
            public void Validate(object value, IPropertyValidationResultsBuilder results)
            {
                if (null != value)
                {
                    // Ensure the value type is integer.
                    if (typeof(Int32) != value.GetType())
                    {
                        throw new InvalidOperationException("Unsupported data type.");
                    }
    
                    int intValue = (int)value;
    
                    // First validation rule: value should be greater than 0.
                    if (intValue <= 0)
                    {
                        results.AddPropertyError("Value should be greater than 0");
                    }
                }
            }
        }
    }
    

    En este código, un validador para el tipo empresarial implementa la interfaz IAttachedPropertyValidation, que define una función llamada Validate. Se llamará a esta función en cualquier momento en que el tipo empresarial deba validarse; puede obtener el valor de datos del valor de parámetro y agregar el resultado de la validación de nuevo al parámetro results.

    A continuación, debe definir un atributo de validación que se pueda usar en el validador.

Para definir un atributo de validación

  1. En el Explorador de soluciones, elija el proyecto BusinessTypeExtension.Common, expanda los nodos Metadatos y Tipos y, a continuación, abra el menú contextual del archivo PositiveInteger.lsml y elija Abrir con.

  2. En el cuadro de diálogo Abrir con, elija Editor XML (texto) y, a continuación, elija el botón Aceptar.

  3. Agregue el código siguiente al elemento SemanticType.Attributes, justo después de la línea <DisplayName Value="Positive Integer" />.

    <Attribute Class="@PositiveIntegerValidation">
         </Attribute>
    
  4. Agregue el código siguiente después del elemento SemanticType:

    <AttributeClass Name="PositiveIntegerValidation">
    
        <AttributeClass.Attributes>
          <Validator />
          <SupportedType Type="PositiveInteger?" />
        </AttributeClass.Attributes>
          </AttributeClass>
    

    A continuación, debe definir un valor ValidatorFactory.

Para crear un valor ValidatorFactory

  1. En el Explorador de soluciones, elija el proyecto BusinessTypeExtension.Common y, a continuación, abra el archivo PositiveIntegerValidation.

  2. Agregue el código siguiente bajo la clase PositiveIntegerValidation para implementar la clase PositiveIntegerValidationFactory.

    <Export(GetType(IValidationCodeFactory))>
    <ValidationCodeFactory(BusinessTypeExtensionModule.PositiveInteger.ValidationAttribute.GlobalName)>
    Public Class PositiveIntegerValidationFactory
        Implements IValidationCodeFactory
    
        Public Function Create(modelItem As Microsoft.LightSwitch.Model.IStructuralItem, attributes As System.Collections.Generic.IEnumerable(Of Microsoft.LightSwitch.Model.IAttribute)) As Microsoft.LightSwitch.Runtime.Rules.IAttachedValidation Implements Microsoft.LightSwitch.Runtime.Rules.IValidationCodeFactory.Create
    
            If Not IsValid(modelItem) Then
                Throw New InvalidOperationException("Unsupported data type.")
            End If
    
            Return New PositiveIntegerValidation(attributes)
    
        End Function
    
        Public Function IsValid(modelItem As Microsoft.LightSwitch.Model.IStructuralItem) As Boolean Implements Microsoft.LightSwitch.Runtime.Rules.IValidationCodeFactory.IsValid
    
            Dim nullableType As INullableType = TryCast(modelItem, INullableType)
    
            ' Get underlying type if it is a INullableType.
            modelItem = If(nullableType IsNot Nothing, nullableType.UnderlyingType, modelItem)
    
            ' Ensure that type is a positive integer semantic type, or that a type inherits from it.
            While TypeOf modelItem Is ISemanticType
                If String.Equals(DirectCast(modelItem, ISemanticType).Id, BusinessTypeExtensionModule.PositiveInteger.GlobalName, StringComparison.Ordinal) Then
                    Return True
                End If
                modelItem = DirectCast(modelItem, ISemanticType).UnderlyingType
            End While
    
    
            ' If the conditions aren't met, LightSwitch will not display the validation rule for
            '   this model item.
            Return False
    
        End Function
    
    End Class
    
    [Export(typeof(IValidationCodeFactory))]
        [ValidationCodeFactory(BusinessTypeExtensionModule.PositiveInteger.ValidationAttribute.GlobalName)]
        public class PositiveIntegerValidatorFactory : IValidationCodeFactory
        {
            public IAttachedValidation Create(IStructuralItem modelItem, IEnumerable<IAttribute> attributes)
            {
                // Enusre that the type model item is a positive integer semantic type (or nullable positive integer)
                if (!IsValid(modelItem)).
                {
                    throw new InvalidOperationException("Unsupported data type.");
                }
    
                return new PositiveIntegerValidator(attributes);
            }
    
            public bool IsValid(IStructuralItem modelItem)
            {
                INullableType nullableType = modelItem as INullableType;
    
                // Get underlying type if it is an INullableType.
                modelItem = null != nullableType ? nullableType.UnderlyingType : modelItem;
    
                // Ensure that type is a positive integer semantic type, or that a type inherits from it.
                while (modelItem is ISemanticType)
                {
                    if (String.Equals(((ISemanticType)modelItem).Id, BusinessTypeExtensionModule.PositiveInteger.GlobalName, StringComparison.Ordinal))
                    {
                        return true;
                    }
                    modelItem = ((ISemanticType)modelItem).UnderlyingType;
                }
    
                // If the conditions aren't met, LightSwitch will not display the validation rule for
                //   this model item.
                return false;
            }
        }
    

    A continuación, debe agregar un indicador de validaciones para que el control proporcione comentarios si el usuario especifica un valor que no es válido. Si bien puede crear su propio indicador de validaciones para el control, es preferible usar el indicador de validaciones integrado.

Para agregar un indicador de validaciones

  1. En el Explorador de soluciones, elija el proyecto BusinessTypeExtension.Client y, a continuación, abra el archivo PositiveIntegerControl.xaml.

  2. Agregue la referencia de espacio de nombres siguiente.

    xmlns:slu="clr-namespace:Microsoft.LightSwitch.Utilities.SilverlightUtilities;assembly=Microsoft.LightSwitch.Client"
    
  3. Agregue el siguiente código XAML después de la línea de referencia que acaba de agregar.

    ToolTipService.ToolTip="{Binding Description}"
    

    Aunque no es necesario, este habilita el objeto ToolTip en tiempo de ejecución para el control, mostrando el valor de la propiedad Description proporcionado por el desarrollador de la aplicación.

  4. Agregue el siguiente código XAML dentro del elemento <Grid>, bajo la línea <TextBlock Grid.Column="1" Text="{Binding Value}" MinWidth="30"/>:

    <!-- Our data context is an IContentItem instance.  Bind to its StringValue property.  It will 
                 automatically handle Silverlight conversion errors and other behavior. -->
            <slu:ValidatableContentControl ValidationDataSource="{Binding StringValue}" Grid.ColumnSpan="2"/>
    

    Este proporciona la misma validación automática que los controles de LightSwitch integrados.

En este punto, puede probar el comportamiento de nuevo en la instancia experimental. Al ejecutar el proyecto BusinessTypeTest, establezca el valor Puntuación en un número negativo y observe el comportamiento de la validación.

Agregar una propiedad personalizada al tipo empresarial

Siempre se aplican las reglas de validación integradas para un tipo empresarial. Puede que también desee agregar un tipo de validación que el desarrollador de la aplicación pueda activar o desactivar. Para conseguirlo, agregue una propiedad de validación que aparecerá en la ventana Propiedades al seleccionarse el tipo empresarial en el Diseñador de tablas.

El primer paso consiste en actualizar los metadatos con el valor o los valores que el desarrollador de la aplicación desea en el modelo de datos.

Para actualizar los metadatos

  1. En el Explorador de soluciones, elija el proyecto BusinessTypeExtension.Common, expanda los nodos Metadatos y Tipos y, a continuación, abra el menú contextual del archivo PositiveInteger.lsml y elija Abrir con.

  2. En el cuadro de diálogo Abrir con, elija Editor XML (texto) y, a continuación, elija el botón Aceptar.

  3. Agregue el código siguiente al elemento AttributeClass, justo debajo del elemento AttributeClass.Attributes.

    <AttributeProperty Name="ShouldBeEven" MetaType="Boolean">
          <AttributeProperty.Attributes>
            <Category Value="Validation" />
            <DisplayName Value="Should be an even number" />
            <UIEditor Id="CheckBoxEditor"/>
          </AttributeProperty.Attributes>
        </AttributeProperty>
    

    Se agrega una propiedad ShouldBeEven de tipo Boolean a los metadatos de validación para que el desarrollador de la aplicación pueda establecer el valor de la propiedad en la hoja de propiedades del Diseñador de tablas. Observe que se especifica CheckBoxEditor para el atributo UIEditor de la propiedad, lo cual resulta adecuado para una propiedad Boolean. Sin esto, LightSwitch elegirá automáticamente un editor de propiedades para la propiedad de validación en la hoja de propiedades del diseñador. Puede buscar los nombres de todos los editores de propiedades integrados dentro de la clase Microsoft.LightSwitch.Designers.PropertyPages.UI.CommonPropertyValueEditorNames.

  4. Actualice la definición de SemanticType agregando un elemento Property dentro del elemento Attribute, como se indica a continuación.

    <Attribute Class="@PositiveIntegerValidation">
            <Property Name="ShouldBeEven" Value="False"/>
          </Attribute>
    

    Este código especifica que, si no se elige un valor, el valor predeterminado es False.

A continuación, debe agregar algunas constantes para representar la propiedad.

Para agregar constantes

  1. En el Explorador de soluciones, elija el proyecto BusinessTypeExtension.Common y, a continuación, abra el archivo BusinessTypeExtensionModule.vb o BusinessTypeExtensionModule.cs.

  2. Agregue el código siguiente a la clase ValidationAttribute, justo después de la línea Public Const GlobalName As String = AttributePrefix + Name (VB) o public const string GlobalName = AttributePrefix + Name; (C#).

    Public Const ShouldBeEvenPropertyName As String = "ShouldBeEven"
                Public Const ShouldBeEvenPropertyEditorName = GlobalName + ShouldBeEvenPropertyName + "Editor"
    
    public const string ShouldBeEvenPropertyName = "ShouldBeEven";
                    public const string ShouldBeEvenPropertyEditorName = GlobalName + ShouldBeEvenPropertyName + "Editor";
    

    De esta forma se proporcionan constantes para la propiedad y el editor de propiedades.

A continuación se agregará código de validación para la nueva propiedad.

Para agregar código de validación

  1. En el Explorador de soluciones, elija el proyecto BusinessTypeExtension.Common y, a continuación, abra el archivo PositiveIntegerValidation.vb o PositiveIntegerValidation.cs.

  2. Reemplace el método Validate existente por el código siguiente.

    Public Sub Validate(value As Object, results As IPropertyValidationResultsBuilder) Implements Microsoft.LightSwitch.Runtime.Rules.IAttachedPropertyValidation.Validate
            If value IsNot Nothing Then
    
                ' Ensure that the value type is integer.
                If GetType(Integer) IsNot value.GetType() Then
                    Throw New InvalidOperationException("Unsupported data type.")
                End If
    
                Dim intValue As Integer = DirectCast(value, Integer)
    
                ' First validation rule: value should be greater than 0.
                If intValue <= 0 Then
                    results.AddPropertyError("Value should be greater than 0")
                End If
    
                ' Second validation rule: Value should be an even number.
                '  It's a dynamic rule - application developers set a property to specify whether 
                '    they want to enable it or not.
                Dim validationAttribute As IAttribute = Me.attributes.FirstOrDefault()
                If validationAttribute IsNot Nothing AndAlso
                    validationAttribute.Class IsNot Nothing AndAlso
                    validationAttribute.Class.Id = BusinessTypeExtensionModule.PositiveInteger.ValidationAttribute.GlobalName AndAlso
                    DirectCast(validationAttribute(BusinessTypeExtensionModule.PositiveInteger.ValidationAttribute.ShouldBeEvenPropertyName), Boolean) AndAlso
                    Not intValue Mod 2 = 0 Then
    
                    results.AddPropertyResult("Value should be an even number", ValidationSeverity.Error)
    
                End If
    
            End If
        End Sub
    
    public void Validate(object value, IPropertyValidationResultsBuilder results)
            {
                if (null != value)
                {
                    // Ensure that the value type is integer.
                    if (typeof(Int32) != value.GetType())
                    {
                        throw new InvalidOperationException("Unsupported data type.");
                    }
    
                    int intValue = (int)value;
    
                    // First validation rule: value should be greater than 0.
                    if (intValue <= 0)
                    {
                        results.AddPropertyError("Value should be greater than 0");
                    }
    
                    // Second validation rule: Value should be an even number.
                    // It's a dynamic rule - application developers set a property to specify whether 
                    //   they want to enable it or not.
                    IAttribute validationAttribute = _attributes.FirstOrDefault();
                    if (validationAttribute != null &&
                        validationAttribute.Class != null &&
                        validationAttribute.Class.Id == BusinessTypeExtensionModule.PositiveInteger.ValidationAttribute.GlobalName &&
                        (bool)validationAttribute[BusinessTypeExtensionModule.PositiveInteger.ValidationAttribute.ShouldBeEvenPropertyName] &&
                        intValue % 2 != 0)
                    {
                        results.AddPropertyResult("Value should be an even number", ValidationSeverity.Error);
                    }
                }
            }
    

    Este código agrega una segunda regla de validación que provoca un error de validación si el valor no es un número par.

En este punto, puede probar el comportamiento de nuevo en la instancia experimental. En el proyecto BusinessTypeTest, abra el Diseñador de tablas y seleccione el campo Puntuación. Observe que la propiedad Should be an even number aparece ahora en la sección Validation de la ventana Propiedades. Cambie el valor de la propiedad y observe el comportamiento en la aplicación en ejecución.

Compilar un editor de propiedades para las propiedades de tipo empresarial

Si el editor de propiedades integrado no satisface sus necesidades, puede compilar su propio editor de propiedades. Por ejemplo, el tipo empresarial PhoneNumber proporciona un editor externo para establecer formatos de número de teléfono.

En este ejemplo, se compila un editor de propiedades de Windows Presentation Foundation (WPF) que muestra un cuadro de diálogo para la propiedad Should be an even number. A diferencia de los editores de propiedades de control, solo es necesario implementar una versión en tiempo de diseño del editor. Las propiedades de tipo empresarial no están disponibles en el Diseñador de pantallas en tiempo de ejecución.

El primer paso es agregar algunas referencias.

Para agregar referencias

  1. En el Explorador de soluciones, abra el menú contextual del proyecto BusinessTypeExtension.Design y, a continuación, elija Agregar referencia.

  2. En el cuadro de diálogo Agregar referencia, agregue una referencia a Microsoft.LightSwitch.ExtensionProvider.dll.

    La ubicación típica de este archivo está en la carpeta C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\LightSwitch\v4.0.

  3. Abra el menú contextual para el nodo BusinessTypeExtension.Design y, a continuación, elija Agregar elemento existente.

  4. Vaya al proyecto BusinessTypeExtension.Common en la solución y, a continuación, elija BusinessTypeExtensionModule.vb o BusinessTypeExtensionModule.cs.

  5. En la lista desplegable del botón Agregar, elija Agregar como vínculo.

    Esto permite que el proyecto Design comparta las constantes que ya ha definido.

El paso siguiente consiste en crear el cuadro de diálogo de WPF que se usará para editar la propiedad de validación.

Para crear un cuadro de diálogo de WPF

  1. En el Explorador de soluciones, abra el menú contextual del proyecto BusinessTypeExtension.Design y, a continuación, elija Agregar nuevo elemento.

  2. En el cuadro de diálogo Agregar nuevo elemento, expanda el nodo WPF y elija Control de usuario (WPF).

  3. En el campo Nombre, escriba ShouldBeEvenEditorDialog y, a continuación, haga clic en Agregar.

  4. Abra el archivo de código subyacente ShouldBeEvenEditorDialog.xaml.vb o ShouldBeEvenEditorDialog.xaml.cs y reemplace el contenido por el código siguiente:

    Imports System.Windows
    
    Public Class ShouldBeEvenEditorDialog
        Inherits Window
        Public Property Value As Nullable(Of Boolean)
            Get
                Return MyBase.GetValue(ShouldBeEvenEditorDialog.ValueProperty)
            End Get
            Set(value As Nullable(Of Boolean))
                MyBase.SetValue(ShouldBeEvenEditorDialog.ValueProperty, value)
            End Set
        End Property
    
        Public Shared ReadOnly ValueProperty As DependencyProperty =
            DependencyProperty.Register(
                "Value",
                GetType(Nullable(Of Boolean)),
                GetType(ShouldBeEvenEditorDialog),
                New UIPropertyMetadata(False))
    
    End Class
    
    using System.Windows;
    
    namespace BusinessTypeExtension
    {
        /// <summary>
        /// Interaction logic for EditorDialog.xaml
        /// </summary>
        public partial class ShouldBeEvenEditorDialog : Window
        {
            public ShouldBeEvenEditorDialog()
            {
                InitializeComponent();
            }
    
            public bool? Value
            {
                get { return (bool?)GetValue(ValueProperty); }
                set { SetValue(ValueProperty, value); }
            }
            public static readonly DependencyProperty ValueProperty =
                DependencyProperty.Register("Value", typeof(bool?), typeof(ShouldBeEvenEditorDialog), new UIPropertyMetadata(false));
        }
    }
    
  5. Abra el archivo ShouldBeEvenEditorDialog.xaml y, a continuación, reemplace el contenido por el código siguiente:

    <Window x:Class="BusinessTypeExtension.ShouldBeEvenEditorDialog"
            xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
            WindowStartupLocation="CenterOwner"
            ShowInTaskbar="False"
            ResizeMode="NoResize"
            Title="Business Type Property Editor" Height="200" Width="300">
        <Grid>
            <CheckBox
                IsChecked="{Binding Value, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Mode=TwoWay}"
                Content="Should be even number"
                HorizontalAlignment="Center"
                VerticalAlignment="Center"
                />
        </Grid>
    </Window>
    

    Este código define un cuadro de diálogo que contiene un control CheckBox para la propiedad.

El paso siguiente consiste en agregar un diccionario de recursos WPF al proyecto BusinessTypeExtension.Design que contenga la implementación.

No se puede conectar el cuadro de diálogo a la hoja de propiedades de LightSwitch directamente. Debe mostrar una etiqueta de vínculo en la hoja de propiedades y mostrar el cuadro de diálogo cuando el desarrollador de la aplicación haga clic en el vínculo.

En tiempo de diseño, LightSwitch requiere implementar una interfaz IPropertyValueEditorProvider, que proporciona un objeto DataTemplate que se usa para crear un control hospedado en la hoja de propiedades. El objeto DataContext del control se establecerá como instancia de IBindablePropertyEntry, que el control usa para tener acceso al valor, el nombre y otra información sobre la propiedad.

Para agregar un diccionario de recursos

  1. En el Explorador de soluciones, abra el menú contextual del proyecto BusinessTypeExtension.Design y, a continuación, elija Agregar nuevo elemento.

  2. En el cuadro de diálogo Agregar nuevo elemento, expanda el nodo WPF y, a continuación, elija Control de usuario (WPF).

  3. En el campo Nombre, escriba EditorTemplates y elija el botón Agregar.

  4. Reemplace el código existente con el siguiente código:

    <ResourceDictionary
        xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:self="clr-namespace:BusinessTypeExtension">
    
        <DataTemplate x:Key="ShouldBeEvenEditorTemplate">
            <Label>
                <Hyperlink
                    Command="{Binding EditorContext}"
                    ToolTip="{Binding Entry.Description}">
                    <Run
                        Text="{Binding Entry.DisplayName, Mode=OneWay}"
                        FontFamily="{DynamicResource DesignTimeFontFamily}"
                        FontSize="{DynamicResource DesignTimeFontSize}"
                        />
                </Hyperlink>
            </Label>
        </DataTemplate>
    
    </ResourceDictionary>
    

    Esto proporciona el hipervínculo que se mostrará en la hoja de propiedades del Diseñador de tablas.

    Nota

    En este punto, aparecerá un error en el código XAML.Puede omitirlo por ahora; el espacio de nombres al que se hace referencia se agregará más adelante.

El paso siguiente consiste en crear un control de editor de propiedades, una tarea sencilla. La clave es tener un hipervínculo y enlazarlo a EditorContext, que debe ser un objeto ICommand de WPF proporcionado por el editor. Después, debe crear un editor para exponer este control a LightSwitch Designer y además implementar el comando en el editor.

Para crear el control de editor de propiedades

  1. En el Explorador de soluciones, abra el menú contextual del proyecto BusinessTypeExtension.Design y, a continuación, elija Agregar nuevo elemento.

  2. En el cuadro de diálogo Agregar nuevo elemento, elija el nodo Código y, a continuación, Clase.

  3. En el campo Nombre, escriba ShouldBeEvenEditor y elija el botón Agregar.

  4. Reemplace el contenido por el código siguiente.

    Imports System
    Imports System.ComponentModel.Composition
    Imports System.Runtime.InteropServices
    Imports System.Windows
    Imports System.Windows.Input
    Imports System.Windows.Interop
    Imports Microsoft.LightSwitch.Designers.PropertyPages
    Imports Microsoft.LightSwitch.Designers.PropertyPages.UI
    
    Friend Class ShouldBeEvenEditor
        Implements IPropertyValueEditor
    
        Public Sub New(entry As IPropertyEntry)
            Me.command = New EditCommand(entry)
        End Sub
    
        Private command As ICommand
    
        Public ReadOnly Property Context As Object Implements Microsoft.LightSwitch.Designers.PropertyPages.UI.IPropertyValueEditor.Context
            Get
                Return Me.command
            End Get
        End Property
    
        Public Function GetEditorTemplate(entry As Microsoft.LightSwitch.Designers.PropertyPages.IPropertyEntry) As System.Windows.DataTemplate Implements Microsoft.LightSwitch.Designers.PropertyPages.UI.IPropertyValueEditor.GetEditorTemplate
            Dim dict As ResourceDictionary = New ResourceDictionary()
            dict.Source = New Uri("BusinessTypeExtension.Design;component/EditorTemplates.xaml", UriKind.Relative)
            Return dict("ShouldBeEvenEditorTemplate")
        End Function
    
        Private Class EditCommand
            Implements ICommand
    
            Public Sub New(entry As IPropertyEntry)
                Me.entry = entry
            End Sub
    
            Private entry As IPropertyEntry
    
            Public Function CanExecute(parameter As Object) As Boolean Implements System.Windows.Input.ICommand.CanExecute
                Return True
            End Function
    
            Public Event CanExecuteChanged(sender As Object, e As System.EventArgs) Implements System.Windows.Input.ICommand.CanExecuteChanged
    
            Public Sub Execute(parameter As Object) Implements System.Windows.Input.ICommand.Execute
    
                Dim dialog As ShouldBeEvenEditorDialog = New ShouldBeEvenEditorDialog()
                dialog.Value = Me.entry.PropertyValue.Value
    
                ' Set the parent window of your dialog box to the IDE window; this ensures the win32 window stack works correctly.
                Dim wih As WindowInteropHelper = New WindowInteropHelper(dialog)
                wih.Owner = GetActiveWindow()
    
                dialog.ShowDialog()
    
                Me.entry.PropertyValue.Value = dialog.Value
    
            End Sub
    
            ''' <summary>
            ''' GetActiveWindow is a Win32 method; we import the method to get the IDE window
            ''' </summary>
            Declare Function GetActiveWindow Lib "User32" () As IntPtr
    
        End Class
    
    End Class
    
    <Export(GetType(IPropertyValueEditorProvider))>
    <PropertyValueEditorName(BusinessTypeExtensionModule.PositiveInteger.ValidationAttribute.ShouldBeEvenPropertyEditorName)>
    <PropertyValueEditorType("System.Boolean")>
    Friend Class ShouldBeEventEditorProvider
        Implements IPropertyValueEditorProvider
    
        Public Function GetEditor(entry As Microsoft.LightSwitch.Designers.PropertyPages.IPropertyEntry) As Microsoft.LightSwitch.Designers.PropertyPages.UI.IPropertyValueEditor Implements Microsoft.LightSwitch.Designers.PropertyPages.UI.IPropertyValueEditorProvider.GetEditor
            Return New ShouldBeEvenEditor(entry)
        End Function
    
    End Class
    
    using System;
    using System.ComponentModel.Composition;
    using System.Runtime.InteropServices;
    using System.Windows;
    using System.Windows.Input;
    using System.Windows.Interop;
    using Microsoft.LightSwitch.Designers.PropertyPages;
    using Microsoft.LightSwitch.Designers.PropertyPages.UI;
    
    namespace BusinessTypeExtension
    {
    
    internal class ShouldBeEvenEditor : IPropertyValueEditor
        {
            public ShouldBeEvenEditor(IPropertyEntry entry)
            {
                _editCommand = new EditCommand(entry);
            }
            private ICommand _editCommand;
    
            public object Context
            {
                get { return _editCommand; }
            }
    
            public DataTemplate GetEditorTemplate(IPropertyEntry entry)
            {
                ResourceDictionary dict = new ResourceDictionary() { Source = new Uri("BusinessTypeExtension.Design;component/EditorTemplates.xaml", UriKind.Relative) };
                return (DataTemplate)dict["ShouldBeEvenEditorTemplate"];
            }
    
            private class EditCommand : ICommand
            {
                public EditCommand(IPropertyEntry entry)
                {
                    _entry = entry;
                }
    
                private IPropertyEntry _entry;
    
                #region ICommand Members
    
                bool ICommand.CanExecute(object parameter)
                {
                    return true;
                }
    
                public event EventHandler CanExecuteChanged { add { } remove { } }
    
                void ICommand.Execute(object parameter)
                {
                    ShouldBeEvenEditorDialog dialog = new ShouldBeEvenEditorDialog() { Value = (bool?)_entry.PropertyValue.Value };
    
                    // Set the parent window of your dialog box to the IDE window; this ensures that the win32 window stack works correctly.
                    WindowInteropHelper wih = new WindowInteropHelper(dialog);
                    wih.Owner = GetActiveWindow();
    
                    dialog.ShowDialog();
    
                    _entry.PropertyValue.Value = dialog.Value;
                }
    
                #endregion
    
                /// <summary>
                /// GetActiveWindow is a Win32 method; we import the method to get the IDE window.
                /// </summary>
                [DllImport("user32")]
                public static extern IntPtr GetActiveWindow();
            }
        }
    
    
        [Export(typeof(IPropertyValueEditorProvider))]
        [PropertyValueEditorName(BusinessTypeExtensionModule.PositiveInteger.ValidationAttribute.ShouldBeEvenPropertyEditorName)]
        [PropertyValueEditorType("System.Boolean")]
        internal class ShouldBeEvenEditorProvider : IPropertyValueEditorProvider
        {
            public IPropertyValueEditor GetEditor(IPropertyEntry entry)
            {
                return new ShouldBeEvenEditor(entry);
            }
        }
    }
    

    El código de este ejemplo expone un componente denominado con un atributo PropertyValueEditorName. LightSwitch Designer cargará este componente cuando el diseñador deba mostrar una propiedad con su valor UIEditor establecido en la misma cadena que el valor del atributo PropertyValueEditorName.

    LightSwitch Designer creará una instancia de IPropertyValueEditor desde el generador y obtendrá los objetos DataTemplate y Context, que es opcional. El diseñador usa DataTemplate para crear el control de interfaz de usuario y lo hospeda en la hoja de propiedades. El control puede tener acceso al objeto de contexto a través de una propiedad EditorContext de su DataContext.

    El editor proporciona un objeto de contexto especial, que es en realidad una interfaz ICommand. El control de interfaz de usuario se enlaza a ICommand. Por consiguiente, se ejecutará cuando el desarrollador de la aplicación haga clic en el vínculo. El cuadro de diálogo aparece y confirma el valor dentro del objeto de comando.

  5. En la barra de menús, elija Compilar y Build BusinessTypeExtension.Design.

    Al compilar, se resolverá el error del espacio de nombres que falta en el archivo EditorTemplates.xaml.

Como último paso, debe enlazar el editor de propiedades mediante la actualización de los metadatos para el tipo empresarial.

Para enlazar el editor de propiedades

  1. En el Explorador de soluciones, elija el proyecto BusinessTypeExtension.Common.

  2. Expanda los nodos Metadatos y Tipos, abra el menú contextual del archivo PositiveInteger.lsml y elija Abrir con.

  3. En el cuadro de diálogo Abrir con, elija Editor XML (texto) y, a continuación, elija el botón Aceptar.

  4. Reemplace el elemento <UIEditor Id="CheckBoxEditor"/> del elemento AttributeProperty por el código siguiente.

    <!--<UIEditor Id="CheckBoxEditor"/>-->
            <Description Value="Modify this property in a dialog" />
            <UIEditor Id="BusinessTypeExtension:@PositiveIntegerValidationShouldBeEvenEditor" />
    

    Esto indica a LightSwitch que use el cuadro de diálogo para mostrar la propiedad.

    El tipo empresarial PositiveInteger ya está completado y puede probarlo de nuevo en la instancia experimental. Seleccione el campo Puntuación en el editor de tablas y observe que ahora se muestra un hipervínculo para la propiedad Should be an even number en la ventana Propiedades. Haga clic en el hipervínculo para mostrar el editor personalizado.

Pasos siguientes

Con esto se completa el tutorial referente a los tipos empresariales; ahora debería tener una extensión de tipo empresarial totalmente operativa que podrá volver a usar en cualquier proyecto de LightSwitch. Esto ha sido solo un ejemplo de un tipo empresarial; puede que desee crear un tipo empresarial cuyo comportamiento sea considerablemente distinto o que use un control diferente. Se aplican los mismos pasos y principios básicos a cualquier extensión de tipo empresarial, si bien hay otros conceptos que se aplican en situaciones distintas. Por ejemplo, puede que desee que el control del tipo empresarial admita datos de solo lectura o admita la edición dentro de un control DataGrid. Para obtener más información, vea Conceptos adicionales sobre el control LightSwitch.

Si va a distribuir la extensión, debe realizar algunas acciones más. Para asegurarse de que la información que se muestra para la extensión en el Diseñador de proyectos y en el Administrador de extensiones es correcta, actualice las propiedades del paquete VSIX. Para obtener más información, vea Cómo: Establecer propiedades de paquete VSIX. Además, hay varios aspectos que deberá considerar si va a distribuir la extensión públicamente. Para obtener más información, vea Cómo: Distribuir una extensión de LightSwitch.

Vea también

Tareas

Cómo: Crear varios controles para un tipo de negocios

Cómo: Crear un control LightSwitch

Cómo: Distribuir una extensión de LightSwitch

Cómo: Establecer propiedades de paquete VSIX

Conceptos

Conceptos adicionales sobre el control LightSwitch

Definir, invalidar y usar propiedades de control de LightSwitch

LightSwitch Extensibility Toolkit para Visual Studio 2013