Compartir a través de


Usar el contexto de interfaz de usuario basada en reglas para extensiones de Visual Studio

Visual Studio permite cargar VSPackages cuando se activan determinados valores conocidos UIContext. Sin embargo, estos contextos de interfaz de usuario no son específicos, lo que deja a los autores de extensiones sin otra posibilidad que no sea elegir un contexto de interfaz de usuario disponible que se activa antes del punto en el que realmente quería que se cargara el VSPackage. Para obtener una lista de contextos de interfaz de usuario conocidos, consulte KnownUIContexts.

La carga de paquetes puede afectar al rendimiento y cargarlos antes de lo necesario, por lo que no es el procedimiento recomendado. Visual Studio 2015 introdujo el concepto de contextos de interfaz de usuario basados en reglas, un mecanismo que permite a los autores de extensiones definir las condiciones precisas en las que se activa un contexto de interfaz de usuario y se cargan los VSPackages asociados.

Contexto de interfaz de usuario basado en reglas

Una “Regla” consta de un nuevo contexto de interfaz de usuario (un GUID) y una expresión booleana que hace referencia a uno o varios “Términos” combinados con operaciones lógicas “y”, “o” o “no”. Los “Términos” se evalúan dinámicamente en tiempo de ejecución y la expresión se vuelve a evaluar siempre que cambie cualquiera de sus términos. Cuando la expresión se evalúa como true, se activa el contexto de interfaz de usuario asociado. De lo contrario, se desactiva el contexto de la interfaz de usuario.

El contexto de la interfaz de usuario basado en reglas se puede usar de varias maneras:

  1. Especifique restricciones de visibilidad para comandos y ventanas de herramientas. Puede ocultar las ventanas de comandos o herramientas hasta que se cumpla la regla de contexto de la interfaz de usuario.

  2. Como restricciones de carga automática: los paquetes de carga automática solo se cumplen cuando se cumple la regla.

  3. Como tarea retrasada: retrasa la carga hasta que se haya superado un intervalo especificado y se cumpla la regla.

    Cualquier extensión de Visual Studio puede usar el mecanismo.

Creación de un contexto de interfaz de usuario basado en reglas

Supongamos que tiene una extensión denominada TestPackage, que ofrece un comando de menú que solo se aplica a los archivos con la extensión .config. Antes de VS2015, la mejor opción era cargar TestPackage cuando se activaba el contexto de la interfaz de usuario SolutionExistsAndFullyLoadedContext. La carga de TestPackage de esta manera no resulta eficaz, ya que es posible que la solución cargada no contenga incluso un archivo .config. Estos pasos muestran cómo se puede usar el contexto de interfaz de usuario basado en reglas para activar un contexto de interfaz de usuario solo cuando se selecciona un archivo con la extensión .config y cargar TestPackage cuando se activa ese contexto de interfaz de usuario.

  1. Defina un nuevo GUID de contexto de interfaz de usuario y agregue a la clase de VSPackage ProvideAutoLoadAttribute y ProvideUIContextRuleAttribute.

    Por ejemplo, supongamos que se va a agregar un nuevo UIContext “UIContextGuid”. El GUID creado (puede crear un GUID haciendo clic en Herramientas>Crear GUID) es “8B40D5E2-5626-42AE-99EF-3DD1EFF46E7B”. A continuación, agregue la siguiente declaración dentro de la clase de paquete:

    public const string UIContextGuid = "8B40D5E2-5626-42AE-99EF-3DD1EFF46E7B";
    

    Para los atributos, agregue los siguientes valores: (Los detalles de estos atributos se explicarán más adelante).

    [ProvideAutoLoad(TestPackage.UIContextGuid)]
    [ProvideUIContextRule(TestPackage.UIContextGuid,
        name: "Test auto load",
        expression: "DotConfig",
        termNames: new[] { "DotConfig" },
        termValues: new[] { "HierSingleSelectionName:.config$" })]
    

    Estos metadatos definen el nuevo GUID de UIContext (8B40D5E2-5626-42AE-99EF-3DD1EFF46E7B) y una expresión que hace referencia a un único término, “DotConfig”. El término “DotConfig” se evalúa como true siempre que la selección actual de la jerarquía activa tenga un nombre que coincida con el patrón de expresión regular “\.config$¨ (termina en .config). El valor (predeterminado) define un nombre opcional para la regla útil para la depuración.

    Los valores del atributo se agregan a pkgdef generados durante el tiempo de compilación posteriormente.

  2. En el archivo VSCT de los comandos de TestPackage, agregue la marca “DynamicVisibility” a los comandos adecuados:

    <CommandFlag>DynamicVisibility</CommandFlag>
    
  3. En la sección VisibilityConstraints del VSCT, vincule los comandos adecuados al nuevo GUID de UIContext definido en el n.º 1:

    <VisibilityConstraints>
        <VisibilityItem guid="guidTestPackageCmdSet" id="TestId"  context="UIContextGuid"/>
    </VisibilityConstraints>
    
  4. En la sección Símbolos, agregue la definición del UIContext:

    <GuidSymbol name="UIContextGuid" value="{8B40D5E2-5626-42AE-99EF-3DD1EFF46E7B}" />
    

    Ahora, los comandos de menú contextual de los archivos *.config solo estarán visibles cuando el elemento seleccionado en el explorador de soluciones sea un archivo .config y el paquete no se cargará hasta que se seleccione uno de esos comandos.

    A continuación, use un depurador para confirmar que el paquete solo se carga cuando está previsto. Para depurar TestPackage:

  5. Establezca un punto de interrupción en el método Initialize.

  6. Compile TestPackage e inicie la depuración.

  7. Cree o abra un proyecto.

  8. Seleccione cualquier archivo con una extensión distinta de .config. No se debe alcanzar el punto de interrupción.

  9. Seleccione el archivo App.Config.

    TestPackage se carga y se detiene en el punto de interrupción.

Adición de más reglas para el contexto de la interfaz de usuario

Dado que las reglas de contexto de la interfaz de usuario son expresiones booleanas, puede agregar reglas más restringidas para un contexto de interfaz de usuario. Por ejemplo, en el contexto de la interfaz de usuario anterior, puede especificar que la regla solo se aplica cuando se carga una solución con un proyecto. De este modo, los comandos no se mostrarán si abre un archivo .config como archivo independiente, no como parte de un proyecto.

[ProvideAutoLoad(TestPackage.UIContextGuid)]
[ProvideUIContextRule(TestPackage.UIContextGuid,
    name: "Test auto load",
    expression: "(SingleProject | MultipleProjects) & DotConfig",
    termNames: new[] { "SingleProject", "MultipleProjects","DotConfig" },
    termValues: new[] { VSConstants.UICONTEXT.SolutionHasSingleProject_string , VSConstants.UICONTEXT.SolutionHasMultipleProjects_string , "HierSingleSelectionName:.config$" })]

Ahora la expresión hace referencia a tres términos. Los dos primeros términos, “SingleProject” y “MultipleProjects”, hacen referencia a otros contextos de interfaz de usuario conocidos (por sus GUID). El tercer término, “DotConfig” es el contexto de interfaz de usuario basado en reglas definido anteriormente en este artículo.

Activación diferida

Las reglas pueden tener un “Retraso” opcional. El retraso se especifica en milisegundos. Si está presente, el retraso hace que la activación o desactivación del contexto de la interfaz de usuario de una regla se retrase en ese intervalo de tiempo. Si la regla cambia antes del intervalo de retraso, no ocurre nada. Este mecanismo se puede usar para “escalonar” los pasos de inicialización, especialmente la inicialización única sin depender de temporizadores ni de registrarse para las notificaciones inactivas.

Por ejemplo, puede especificar la regla de carga de prueba para que tenga un retraso de 100 milisegundos:

[ProvideAutoLoad(TestPackage.UIContextGuid)]
[ProvideUIContextRule(TestPackage.UIContextGuid,
    name: "Test auto load",
    expression: "DotConfig",
    termNames: new[] { "DotConfig" },
    termValues: new[] { "HierSingleSelectionName:.config$" },
    delay: 100)]

Tipos de términos

Estos son los distintos tipos de términos que se admiten:

Término Descripción
{nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn} El GUID hace referencia a un contexto de interfaz de usuario. El término será true siempre que el contexto de la interfaz de usuario esté activo y false de lo contrario.
HierSingleSelectionName:<pattern> El término será true siempre que la selección de la jerarquía activa sea un solo elemento y el nombre del elemento seleccionado coincida con la expresión regular .NET dada por “pattern”.
UserSettingsStoreQuery:<query> La expresión “query” representa una ruta de acceso completa al almacén de configuración de usuario, que debe evaluarse como un valor distinto de cero. La consulta se divide en “collection” y “propertyName” en la última barra diagonal.
ConfigSettingsStoreQuery:<query> La expresión “query” representa una ruta de acceso completa al almacén de ajustes de configuración, que debe evaluarse como un valor distinto de cero. La consulta se divide en “collection” y “propertyName” en la última barra diagonal.
ActiveProjectFlavor:<projectTypeGuid> El término será true siempre que el proyecto seleccionado actualmente presente un tipo (agregado) y tenga un tipo que coincida con el GUID de tipo de proyecto especificado.
ActiveEditorContentType:<contentType> El término será true cuando el documento seleccionado sea un editor de texto con el tipo de contenido especificado. Nota: Cuando se cambia el nombre del documento seleccionado, este término no se actualiza hasta que el archivo se cierra y se vuelve a abrir.
ActiveProjectCapability:<Expression> El término es true cuando las funcionalidades del proyecto activo coinciden con la expresión proporcionada. Una expresión puede ser algo parecido a VB | CSharp.
SolutionHasProjectCapability:<Expression> Similar al caso anterior, pero el término es true cuando la solución tiene cualquier proyecto cargado que coincida con la expresión.
SolutionHasProjectFlavor:<projectTypeGuid> El término será true siempre que la solución presente un tipo (agregado) y tenga un tipo que coincida con el GUID de tipo de proyecto especificado.
ProjectAddedItem:<pattern> El término es true cuando se agrega un archivo que coincide con el “pattern” a un proyecto de la solución que está abierto.
ActiveProjectOutputType:<outputType> El término es true cuando el tipo de salida del proyecto activo coincide exactamente. El outputType podría ser un entero o un tipo __VSPROJOUTPUTTYPE.
ActiveProjectBuildProperty:<buildProperty>=<regex> El término es true cuando el proyecto activo tiene la propiedad de compilación especificada y el valor de propiedad coincide con el filtro regex proporcionado. Consulte Conservación de datos en archivos de proyecto MSBuild para obtener más información sobre las propiedades de compilación.
SolutionHasProjectBuildProperty:<buildProperty>=<regex> El término es true cuando la solución tiene un proyecto cargado con la propiedad de compilación y el valor de propiedad especificados coincide con el filtro regex proporcionado.

Compatibilidad con la extensión entre versiones.

Los contextos de interfaz de usuario basados en reglas son una nueva característica de Visual Studio 2015 y no se migrarían a versiones anteriores. El hecho de no migrar a versiones anteriores crea un problema con extensiones o paquetes que tienen como destino varias versiones de Visual Studio. Esas versiones tendrían que cargarse automáticamente en Visual Studio 2013 y versiones anteriores, pero pueden beneficiarse de contextos de interfaz de usuario basados en reglas para evitar que se carguen automáticamente en Visual Studio 2015.

Para admitir estos paquetes, las entradas AutoLoadPackages del registro ahora pueden proporcionar una marca en su campo de valor para indicar que la entrada debe omitirse en Visual Studio 2015 y versiones posteriores. Para ello, agregue una opción de marcas a PackageAutoLoadFlags. VSPackages ahora puede agregar la opción SkipWhenUIContextRulesActive a su atributo ProvideAutoLoadAttribute para indicar que la entrada debe omitirse en Visual Studio 2015 y versiones posteriores.

Reglas de contexto de interfaz de usuario extensibles

A veces, los paquetes no pueden usar reglas de contexto de interfaz de usuario estáticas. Por ejemplo, supongamos que tiene un paquete que admite extensibilidad, de modo que el estado del comando se basa en los tipos de editor admitidos por los proveedores MEF importados. El comando se habilita si hay una extensión que admita el tipo de edición actual. En tales casos, el propio paquete no puede usar una regla de contexto de interfaz de usuario estática, ya que los términos cambiarían en función de las extensiones MEF disponibles.

Para admitir estos paquetes, los contextos de interfaz de usuario basados en reglas admiten una expresión codificada de forma rígida “*” que indica todos los términos siguientes que se combinarán con OR. Esto permite al paquete primario definir un contexto de interfaz de usuario conocido basado en reglas y vincular su estado de comando a este contexto. Después, cualquier extensión MEF destinada al paquete primario puede agregar sus términos para los editores que admite sin que ello afecte a otros términos ni a la expresión primaria.

La documentación del constructor ProvideExtensibleUIContextRuleAttribute muestra la sintaxis de las reglas extensibles de contexto de interfaz de usuario.