Compartir a través de


Plantillas de control

Puedes personalizar la estructura visual y el comportamiento visual de un control mediante la creación de una plantilla de control en el marco XAML. Los controles tienen muchas propiedades, como fondo, primer planoy familia de fuentes, que puede establecer para especificar distintos aspectos de la apariencia del control. Pero los cambios que puede realizar estableciendo estas propiedades son limitados. Puede especificar personalizaciones adicionales mediante la creación de una plantilla mediante la clase ControlTemplate. Aquí le mostramos cómo crear un ControlTemplate de para personalizar la apariencia de un control de CheckBox.

APIs importantes: clase ControlTemplate, propiedad Control.Template

Ejemplo de plantilla de control personalizado

De forma predeterminada, un control CheckBox coloca su contenido (la cadena o el objeto junto a la CheckBox) a la derecha del cuadro de selección y una marca de verificación indica que un usuario seleccionó el CheckBox. Estas características representan la estructura visual y el comportamiento visual del CheckBox.

Este es un checkBox de mediante el ControlTemplate predeterminado que se muestra en los estados , y .

plantilla de casilla predeterminada

Puede cambiar estas características mediante la creación de un ControlTemplate para el CheckBox. Por ejemplo, si desea que el contenido de la casilla esté debajo de la casilla de selección y desea usar una X para indicar que un usuario ha seleccionado la casilla. Especifique estas características en el ControlTemplate del CheckBox.

Para usar una plantilla personalizada con un control, asigne el ControlTemplate a la propiedad Template del control. Este es un CheckBox mediante un ControlTemplate denominado . En la sección siguiente se muestra el lenguaje de marcado extensible de aplicaciones (XAML) para el ControlTemplate de .

<CheckBox Content="CheckBox" Template="{StaticResource CheckBoxTemplate1}" IsThreeState="True" Margin="20"/>

Así es como se ve esta CheckBox en los estados Unchecked, Checkedy Indeterminate después de aplicar nuestra plantilla.

plantilla de casilla personalizada

Especificar la estructura visual de un control

Al crear uncontrolTemplate de , se combinan FrameworkElement objetos para crear un único control. Un ControlTemplate debe tener solo un FrameworkElement como elemento raíz. El elemento raíz normalmente contiene otros objetos FrameworkElement. La combinación de objetos constituye la estructura visual del control.

Este XAML crea un ControlTemplate para un CheckBox que especifica que el contenido del control está debajo del cuadro de selección. El elemento raíz es un Border. El ejemplo especifica un Path para crear una X que indica que un usuario seleccionó el CheckBox , y una Ellipse que indica un estado indeterminado. Tenga en cuenta que la opacidad está establecida en 0 en el camino y la elipse , para que, de forma predeterminada, no aparezca ninguno.

Un TemplateBinding es un enlace especial que vincula el valor de una propiedad de una plantilla de control al valor de alguna otra propiedad expuesta en el control con plantilla. TemplateBinding solo se puede usar dentro de una definición ControlTemplate en XAML. Consulte extensión de marcado TemplateBinding para obtener más información.

Nota:

A partir de Windows 10, versión 1809 (SDK 17763), puedes usar x:Bind extensiones de marcado en lugares en los que usas TemplateBinding. Consulte extensión de marcado TemplateBinding para obtener más información.

<ControlTemplate x:Key="CheckBoxTemplate1" TargetType="CheckBox">
    <Border BorderBrush="{TemplateBinding BorderBrush}"
            BorderThickness="{TemplateBinding BorderThickness}"
            Background="{TemplateBinding Background}">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="*"/>
                <RowDefinition Height="25"/>
            </Grid.RowDefinitions>
            <Rectangle x:Name="NormalRectangle" Fill="Transparent" Height="20" Width="20"
                       Stroke="{ThemeResource SystemControlForegroundBaseMediumHighBrush}"
                       StrokeThickness="{ThemeResource CheckBoxBorderThemeThickness}"
                       UseLayoutRounding="False"/>
            <!-- Create an X to indicate that the CheckBox is selected. -->
            <Path x:Name="CheckGlyph"
                  Data="M103,240 L111,240 119,248 127,240 135,240 123,252 135,264 127,264 119,257 111,264 103,264 114,252 z"
                  Fill="{ThemeResource CheckBoxForegroundThemeBrush}"
                  FlowDirection="LeftToRight"
                  Height="14" Width="16" Opacity="0" Stretch="Fill"/>
            <Ellipse x:Name="IndeterminateGlyph"
                     Fill="{ThemeResource CheckBoxForegroundThemeBrush}"
                     Height="8" Width="8" Opacity="0" UseLayoutRounding="False" />
            <ContentPresenter x:Name="ContentPresenter"
                              ContentTemplate="{TemplateBinding ContentTemplate}"
                              Content="{TemplateBinding Content}"
                              Margin="{TemplateBinding Padding}" Grid.Row="1"
                              HorizontalAlignment="Center"
                              VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
        </Grid>
    </Border>
</ControlTemplate>

Especificar el comportamiento visual de un control

Un comportamiento visual especifica la apariencia de un control cuando se encuentra en un estado determinado. El control CheckBox tiene 3 estados de comprobación: Checked, Uncheckedy Indeterminate. El valor de la propiedad IsChecked determina el estado del CheckBoxy su estado determina lo que aparece en el cuadro.

En esta tabla se enumeran los posibles valores de IsChecked, los estados correspondientes de la CheckBoxy la apariencia de la CheckBox.

valor de IsChecked estado de CheckBox Apariencia del CheckBox de
verdadero Checked Contiene una "X".
falso Unchecked Vacío.
nulo Indeterminate Contiene un círculo.

Se especifica la apariencia de un control cuando se encuentra en un estado determinado mediante objetos VisualState . Un VisualState contiene un Setter o un Storyboard que cambia la apariencia de los elementos en el ControlTemplate. Cuando el control entra en el estado que especifica la propiedad VisualState.Name, se aplican los cambios de propiedad en el Setter o Storyboard. Cuando el control sale del estado, se eliminan los cambios. Agregue objetos VisualState a objetos VisualStateGroup. Agregue objetos VisualStateGroup a la propiedad adjunta VisualStateManager.VisualStateGroups, que estableció en la raíz FrameworkElement de la ControlTemplate.

En este XAML se muestran los objetos VisualState para los estados , y . En el ejemplo se establece la propiedad adjunta VisualStateManager.VisualStateGroups en Border, que es el elemento raíz del ControlTemplate. El CheckedVisualState especifica que la opacidad del Path denominado CheckGlyph (que mostramos en el ejemplo anterior) es 1. El VisualState especifica que el de opacidad de del denominado es 1. El UncheckedVisualState no tiene Setter ni Storyboard, de manera que el CheckBox vuelve a su apariencia predeterminada.

<ControlTemplate x:Key="CheckBoxTemplate1" TargetType="CheckBox">
    <Border BorderBrush="{TemplateBinding BorderBrush}"
            BorderThickness="{TemplateBinding BorderThickness}"
            Background="{TemplateBinding Background}">

        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="CheckStates">
                <VisualState x:Name="Checked">
                    <VisualState.Setters>
                        <Setter Target="CheckGlyph.Opacity" Value="1"/>
                    </VisualState.Setters>
                    <!-- This Storyboard is equivalent to the Setter. -->
                    <!--<Storyboard>
                        <DoubleAnimation Duration="0" To="1"
                         Storyboard.TargetName="CheckGlyph" Storyboard.TargetProperty="Opacity"/>
                    </Storyboard>-->
                </VisualState>
                <VisualState x:Name="Unchecked"/>
                <VisualState x:Name="Indeterminate">
                    <VisualState.Setters>
                        <Setter Target="IndeterminateGlyph.Opacity" Value="1"/>
                    </VisualState.Setters>
                    <!-- This Storyboard is equivalent to the Setter. -->
                    <!--<Storyboard>
                        <DoubleAnimation Duration="0" To="1"
                         Storyboard.TargetName="IndeterminateGlyph" Storyboard.TargetProperty="Opacity"/>
                    </Storyboard>-->
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>

        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="*"/>
                <RowDefinition Height="25"/>
            </Grid.RowDefinitions>
            <Rectangle x:Name="NormalRectangle" Fill="Transparent" Height="20" Width="20"
                       Stroke="{ThemeResource SystemControlForegroundBaseMediumHighBrush}"
                       StrokeThickness="{ThemeResource CheckBoxBorderThemeThickness}"
                       UseLayoutRounding="False"/>
            <!-- Create an X to indicate that the CheckBox is selected. -->
            <Path x:Name="CheckGlyph"
                  Data="M103,240 L111,240 119,248 127,240 135,240 123,252 135,264 127,264 119,257 111,264 103,264 114,252 z"
                  Fill="{ThemeResource CheckBoxForegroundThemeBrush}"
                  FlowDirection="LeftToRight"
                  Height="14" Width="16" Opacity="0" Stretch="Fill"/>
            <Ellipse x:Name="IndeterminateGlyph"
                     Fill="{ThemeResource CheckBoxForegroundThemeBrush}"
                     Height="8" Width="8" Opacity="0" UseLayoutRounding="False" />
            <ContentPresenter x:Name="ContentPresenter"
                              ContentTemplate="{TemplateBinding ContentTemplate}"
                              Content="{TemplateBinding Content}"
                              Margin="{TemplateBinding Padding}" Grid.Row="1"
                              HorizontalAlignment="Center"
                              VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
        </Grid>
    </Border>
</ControlTemplate>

Para comprender mejor cómo funcionan objetos VisualState, tenga en cuenta lo que sucede cuando el checkBox de pasa del estado de al estado de y, a continuación, al estado de y, a continuación, vuelve al estado de . Estas son las transiciones.

Transición de estado ¿Qué ocurre? Apariencia de CheckBox cuando se completa la transición
De Unchecked a Checked. El valor de Setter del CheckedVisualState se aplica, por lo que la Opacidad de CheckGlyph es 1. Se muestra una X.
De Checked a Indeterminate. El valor de Setter del IndeterminateVisualState se aplica, por lo que la Opacidad de IndeterminateGlyph es 1. Se quita el valor Setter del visualState, por lo que el de opacidad de es 0. Se muestra un círculo.
De Indeterminate a Unchecked. Se quita el valor Establecedor del VisualState, por lo que el de opacidad de es 0. No se muestra nada.

 Para obtener más información sobre cómo crear estados visuales para controles y, en particular, cómo usar la clase storyboard de y los tipos de animación, consulta animaciones con guion gráfico para estados visuales.

Uso de herramientas para trabajar con temas fácilmente

Una manera rápida de aplicar temas a los controles es hacer clic con el botón derecho en un control en el Esquema de documento de Microsoft Visual Studio y seleccionar Editar tema o Editar estilo (según el control en el que haga clic con el botón derecho). Después, puede aplicar un tema existente seleccionando Aplicar recurso o definir uno nuevo seleccionando Crear uno vacío.

Controles y accesibilidad

Al crear una nueva plantilla para un control, además de cambiar posiblemente el comportamiento del control y la apariencia visual, es posible que también cambie la forma en que el control se representa a los marcos de accesibilidad. La aplicación de Windows admite el marco de automatización de la interfaz de usuario de Microsoft para la accesibilidad. Todos los controles predeterminados y sus plantillas tienen compatibilidad con los tipos de control y patrones comunes de automatización de la interfaz de usuario que son adecuados para el propósito y la función del control. Estos tipos de control y patrones se interpretan mediante clientes de automatización de la interfaz de usuario, como tecnologías de asistencia, y esto permite que un control sea accesible como parte de una interfaz de usuario de aplicación accesible más grande.

Para separar la lógica de control básica y también para satisfacer algunos de los requisitos arquitectónicos de UI Automation, las clases de control incluyen su soporte de accesibilidad en una clase independiente, un elemento de automatización. A veces, los pares de automatización tienen interacciones con las plantillas de control porque esperan que existan determinados elementos nombrados en las plantillas, de modo que sea posible habilitar funcionalidades como permitir que las tecnologías de asistencia invocan acciones de botones.

Al crear un control personalizado completamente nuevo, a veces también querrá crear un nuevo elemento del mismo nivel de automatización para continuar con él. Para obtener más información, consulte pares de automatización personalizada.

Más información sobre la plantilla predeterminada de un control

Los temas que documentan los estilos y plantillas para los controles XAML ofrecen extractos del mismo XAML inicial que podrías observar si utilizas las técnicas de Editar tema o Editar estilo explicadas anteriormente. Cada tema enumera los nombres de los estados visuales, los recursos del tema usados y el XAML completo para el estilo que contiene la plantilla. Los temas pueden ser útiles si ya ha empezado a modificar una plantilla y desea ver el aspecto de la plantilla original o para comprobar que la nueva plantilla tiene todos los estados visuales con nombre necesarios.

Recursos de tema en plantillas de control

Para algunos de los atributos en los ejemplos de XAML, es posible que hayas observado referencias a recursos que utilizan la extensión de marcado {ThemeResource} con . Se trata de una técnica que permite que una sola plantilla de control use recursos que pueden ser valores diferentes en función del tema que esté activo actualmente. Esto es especialmente importante para pinceles y colores, ya que el propósito principal de los temas es permitir a los usuarios elegir si quieren un tema oscuro, claro o de contraste alto aplicado al sistema en general. Las aplicaciones que usan el sistema de recursos XAML pueden usar un conjunto de recursos adecuado para ese tema, de modo que las opciones de tema de la interfaz de usuario de una aplicación reflejen la elección del tema para todo el sistema del usuario.

Obtención del código de ejemplo