Compartir vía


Tutorial: Crear un botón mediante el uso de XAML

El objetivo de este tutorial es aprender a crear un botón animado para usarlo en una aplicación de Windows Presentation Foundation (WPF). En este tutorial se usan estilos y una plantilla para crear un recurso de botón personalizado que permite reutilizar el código y la separación de la lógica de botón de la declaración del botón. Este tutorial está escrito por completo en lenguaje de marcado de aplicaciones extensibles (XAML).

Importante

Este tutorial le guía por los pasos para crear la aplicación escribiendo o copiando y pegando lenguaje XAML en Visual Studio. Si prefiere aprender a usar un diseñador para crear la misma aplicación, consulte Crear un botón mediante Microsoft Expression Blend.

En la ilustración siguiente se muestran los botones terminados.

Botones personalizados creados mediante XAML

Creación de botones básicos

Comencemos creando un proyecto y agregando algunos botones a la ventana.

Para crear un nuevo proyecto de WPF y agregar botones a la ventana

  1. Inicie Visual Studio.

  2. Cree un nuevo proyecto de WPF: En el menú Archivo, elija Nuevo y, a continuación, haga clic en Proyecto. Busque la plantilla aplicación de Windows (WPF) y asigne al proyecto el nombre "AnimatedButton". Esto creará el esqueleto de la aplicación.

  3. Agregue botones predeterminados básicos: La plantilla proporciona todos los archivos que necesita para este tutorial. Abra el archivo Window1.xaml haciendo doble clic en él en Explorador de soluciones. De forma predeterminada, hay un elemento Grid en Window1.xaml. Quite el elemento Grid y agregue algunos botones a la página de lenguaje XAML escribiendo o copiando y pegando el código resaltado siguiente en Window1.xaml:

    <Window x:Class="AnimatedButton.Window1"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      Title="AnimatedButton" Height="300" Width="300"
      Background="Black">
      <!-- Buttons arranged vertically inside a StackPanel. -->
      <StackPanel HorizontalAlignment="Left">
          <Button>Button 1</Button>
          <Button>Button 2</Button>
          <Button>Button 3</Button>
      </StackPanel>
    </Window>
    

    Presione F5 para ejecutar la aplicación; debería ver un conjunto de botones con un aspecto similar al de la ilustración siguiente.

    Tres botones básicos

    Ahora que ha creado los botones básicos, ha terminado de trabajar en el archivo Window1.xaml. El resto del tutorial se centra en el archivo app.xaml y en definir estilos y una plantilla para los botones.

Establecer las propiedades básicas

A continuación, vamos a establecer algunas propiedades en estos botones para controlar su apariencia y diseño. En lugar de establecer propiedades en los botones individualmente, usará recursos para definir propiedades de botón para toda la aplicación. Los recursos de aplicación son conceptualmente similares a las hojas de estilos en cascada externas (CSS) para las páginas web; sin embargo, los recursos son mucho más eficaces que las hojas de estilo CSS, como verá al final de este tutorial. Para obtener más información acerca de los recursos, consulte Recursos XAML.

Para usar estilos para establecer propiedades básicas en los botones

  1. Defina un bloque Application.Resources: Abra app.xaml y agregue el marcado resaltado siguiente si aún no está ahí:

    <Application x:Class="AnimatedButton.App"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      StartupUri="Window1.xaml"
      >
      <Application.Resources>
        <!-- Resources for the entire application can be defined here. -->
      </Application.Resources>
    </Application>
    

    El ámbito del recurso viene determinado por dónde se define el recurso. La definición de recursos en Application.Resources en el archivo app.xaml permite usar el recurso desde cualquier lugar de la aplicación. Para obtener más información sobre cómo definir el ámbito de los recursos, consulte Recursos XAML.

  2. Cree un estilo y defina los valores de propiedad básicos con él: Agregue el marcado siguiente al bloque Application.Resources. Este marcado crea un objeto Style que se aplica a todos los botones de la aplicación, estableciendo el Width de los botones en 90 y Margin en 10:

    <Application.Resources>
      <Style TargetType="Button">
        <Setter Property="Width" Value="90" />
        <Setter Property="Margin" Value="10" />
      </Style>
    </Application.Resources>
    

    La propiedad TargetType especifica que el estilo se aplica a todos los objetos de tipo Button. Cada Setter establece un valor de propiedad diferente para Style. Por lo tanto, en este punto, cada botón de la aplicación tiene un ancho de 90 y un margen de 10. Si presiona F5 para ejecutar la aplicación, verá la ventana siguiente.

    Botones con ancho de 90 y margen de 10

    Hay mucho más que puede hacer con los estilos, incluyendo ajustar los objetos de destino de varias formas, especificar valores de propiedad complejos e incluso usar estilos como entrada para otros estilos. Para obtener más información, consulte Aplicar estilos y plantillas.

  3. Establezca un valor de propiedad de estilo en un recurso: Los recursos permiten reutilizar los objetos y valores definidos normalmente de una manera sencilla. Es especialmente útil definir valores complejos mediante recursos para que el código sea más modular. Agregue el marcado resaltado siguiente a app.xaml.

    <Application.Resources>
      <LinearGradientBrush x:Key="GrayBlueGradientBrush" StartPoint="0,0" EndPoint="1,1">
        <GradientStop Color="DarkGray" Offset="0" />
        <GradientStop Color="#CCCCFF" Offset="0.5" />
        <GradientStop Color="DarkGray" Offset="1" />
      </LinearGradientBrush>
      <Style TargetType="{x:Type Button}">
        <Setter Property="Background" Value="{StaticResource GrayBlueGradientBrush}" />
        <Setter Property="Width" Value="80" />
        <Setter Property="Margin" Value="10" />
      </Style>
    </Application.Resources>
    

    Ha creado un recurso denominado "GrayBlueGradientBrush" justo debajo del bloque Application.Resources. Este recurso define un degradado horizontal. Este recurso se puede usar como un valor de propiedad desde cualquier lugar de la aplicación, incluido dentro del establecedor de estilo de botón para la propiedad Background. Ahora, todos los botones tienen un valor de propiedad de Background de este degradado.

    Presione F5 para ejecutar la aplicación. Debería tener este aspecto.

    Botones con un fondo degradado

Crear una plantilla que defina el aspecto del botón

En esta sección, creará una plantilla que personaliza la apariencia (presentación) del botón. La presentación del botón se compone de varios objetos, incluidos rectángulos y otros componentes para dar al botón un aspecto único.

Hasta ahora, el control de cómo se ven los botones en la aplicación se ha limitado a cambiar las propiedades del botón. ¿Qué ocurre si desea realizar cambios más radicales en la apariencia del botón? Las plantillas le dan un gran control sobre la presentación de un objeto. Dado que las plantillas se pueden usar dentro de los estilos, puede aplicar una plantilla a todos los objetos a los que se aplica el estilo (en este tutorial, el botón).

Para usar la plantilla para definir el aspecto del botón

  1. Configure la plantilla: Dado que los controles como Button tienen una propiedad Template, puede definir el valor de la propiedad de plantilla igual que los demás valores de propiedad que hemos establecido en Style mediante Setter. Agregue el marcado resaltado siguiente al estilo de botón.

    <Application.Resources>
      <LinearGradientBrush x:Key="GrayBlueGradientBrush"
        StartPoint="0,0" EndPoint="1,1">
        <GradientStop Color="DarkGray" Offset="0" />
        <GradientStop Color="#CCCCFF" Offset="0.5" />
        <GradientStop Color="DarkGray" Offset="1" />
      </LinearGradientBrush>
      <Style TargetType="{x:Type Button}">
        <Setter Property="Background" Value="{StaticResource GrayBlueGradientBrush}" />
        <Setter Property="Width" Value="80" />
        <Setter Property="Margin" Value="10" />
        <Setter Property="Template">
          <Setter.Value>
            <!-- The button template is defined here. -->
          </Setter.Value>
        </Setter>
      </Style>
    </Application.Resources>
    
  2. Modifique presentación del botón: En este momento, debe definir la plantilla. Agregue el marcado resaltado siguiente. Este marcado especifica dos elementos Rectangle con bordes redondeados, seguidos de DockPanel. DockPanel se usa para hospedar el elemento ContentPresenter del botón. Un objeto ContentPresenter muestra el contenido del botón. En este tutorial, el contenido es texto ("Botón 1", "Botón 2", "Botón 3"). Todos los componentes de plantilla (los rectángulos y DockPanel) se colocan dentro de Grid.

    <Setter.Value>
      <ControlTemplate TargetType="Button">
        <Grid Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" ClipToBounds="True">
          <!-- Outer Rectangle with rounded corners. -->
          <Rectangle x:Name="outerRectangle" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Stroke="{TemplateBinding Background}" RadiusX="20" RadiusY="20" StrokeThickness="5" Fill="Transparent" />
          <!-- Inner Rectangle with rounded corners. -->
          <Rectangle x:Name="innerRectangle" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Stroke="Transparent" StrokeThickness="20" Fill="{TemplateBinding Background}" RadiusX="20" RadiusY="20" />
          <!-- Present Content (text) of the button. -->
          <DockPanel Name="myContentPresenterDockPanel">
            <ContentPresenter x:Name="myContentPresenter" Margin="20" Content="{TemplateBinding  Content}" TextBlock.Foreground="Black" />
          </DockPanel>
        </Grid>
      </ControlTemplate>
    </Setter.Value>
    

    Presione F5 para ejecutar la aplicación. Debería tener este aspecto.

    Ventana con 3 botones

  3. Agregue un objeto glasseffect a la plantilla: A continuación, añadirá el objeto glasseffect. En primer lugar, cree algunos recursos que creen un efecto de degradado de vidrio. Agregue estos recursos de degradado en cualquier parte del bloque Application.Resources:

    <Application.Resources>
      <GradientStopCollection x:Key="MyGlassGradientStopsResource">
        <GradientStop Color="WhiteSmoke" Offset="0.2" />
        <GradientStop Color="Transparent" Offset="0.4" />
        <GradientStop Color="WhiteSmoke" Offset="0.5" />
        <GradientStop Color="Transparent" Offset="0.75" />
        <GradientStop Color="WhiteSmoke" Offset="0.9" />
        <GradientStop Color="Transparent" Offset="1" />
      </GradientStopCollection>
      <LinearGradientBrush x:Key="MyGlassBrushResource"
        StartPoint="0,0" EndPoint="1,1" Opacity="0.75"
        GradientStops="{StaticResource MyGlassGradientStopsResource}" />
    <!-- Styles and other resources below here. -->
    

    Estos recursos se usan como Fill para un rectángulo que insertamos en la Grid plantilla de botón. Agregue el marcado resaltado siguiente a la plantilla.

    <Setter.Value>
      <ControlTemplate TargetType="{x:Type Button}">
        <Grid Width="{TemplateBinding Width}" Height="{TemplateBinding Height}"
          ClipToBounds="True">
    
        <!-- Outer Rectangle with rounded corners. -->
        <Rectangle x:Name="outerRectangle" HorizontalAlignment="Stretch"
          VerticalAlignment="Stretch" Stroke="{TemplateBinding Background}"
          RadiusX="20" RadiusY="20" StrokeThickness="5" Fill="Transparent" />
    
        <!-- Inner Rectangle with rounded corners. -->
        <Rectangle x:Name="innerRectangle" HorizontalAlignment="Stretch"
          VerticalAlignment="Stretch" Stroke="Transparent" StrokeThickness="20"
          Fill="{TemplateBinding Background}" RadiusX="20" RadiusY="20" />
    
        <!-- Glass Rectangle -->
        <Rectangle x:Name="glassCube" HorizontalAlignment="Stretch"
          VerticalAlignment="Stretch"
          StrokeThickness="2" RadiusX="10" RadiusY="10" Opacity="0"
          Fill="{StaticResource MyGlassBrushResource}"
          RenderTransformOrigin="0.5,0.5">
          <Rectangle.Stroke>
            <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
              <LinearGradientBrush.GradientStops>
                <GradientStop Offset="0.0" Color="LightBlue" />
                <GradientStop Offset="1.0" Color="Gray" />
              </LinearGradientBrush.GradientStops>
            </LinearGradientBrush>
          </Rectangle.Stroke>
          <!-- These transforms have no effect as they are declared here.
          The reason the transforms are included is to be targets
          for animation (see later). -->
          <Rectangle.RenderTransform>
            <TransformGroup>
              <ScaleTransform />
              <RotateTransform />
            </TransformGroup>
          </Rectangle.RenderTransform>
          <!-- A BevelBitmapEffect is applied to give the button a "Beveled" look. -->
          <Rectangle.BitmapEffect>
            <BevelBitmapEffect />
          </Rectangle.BitmapEffect>
        </Rectangle>
    
        <!-- Present Text of the button. -->
        <DockPanel Name="myContentPresenterDockPanel">
          <ContentPresenter x:Name="myContentPresenter" Margin="20"
            Content="{TemplateBinding  Content}" TextBlock.Foreground="Black" />
        </DockPanel>
      </Grid>
    </ControlTemplate>
    </Setter.Value>
    

    Observe que el Opacity del rectángulo con la propiedad x:Name de "glassCube" es 0, por lo que al ejecutar la muestra, no verá el rectángulo de vidrio superpuesto encima. Esto se debe a que más adelante agregaremos desencadenadores a la plantilla para cuando el usuario interactúe con el botón. Sin embargo, puede ver el aspecto del botón ahora cambiando el valor Opacity a 1 y ejecutando la aplicación. Consulte la siguiente figura. Antes de continuar con el paso siguiente, cambie Opacity de nuevo a 0.

    Botones personalizados creados mediante XAML

Crear interactividad de botón

En esta sección, creará desencadenadores de propiedades y desencadenadores de eventos para cambiar los valores de propiedad y ejecutar animaciones en respuesta a acciones del usuario, como mover el puntero del mouse sobre el botón y hacer clic.

Una manera fácil de agregar interactividad (mouse-over, mouse-leave, click, etc.) es definir desencadenadores dentro de la plantilla o estilo. Para crear un Trigger, defina una propiedad "condition" como: El valor de la propiedad del botón IsMouseOver es igual a true. A continuación, se definen establecedores (acciones) que tienen lugar cuando la condición del desencadenador es verdadera.

Para crear interactividad de botón

  1. Agregue desencadenadores de plantilla: Agregue el marcado resaltado a la plantilla.

    <Setter.Value>
      <ControlTemplate TargetType="{x:Type Button}">
        <Grid Width="{TemplateBinding Width}"
          Height="{TemplateBinding Height}" ClipToBounds="True">
    
          <!-- Outer Rectangle with rounded corners. -->
          <Rectangle x:Name="outerRectangle" HorizontalAlignment="Stretch"
          VerticalAlignment="Stretch" Stroke="{TemplateBinding Background}"
          RadiusX="20" RadiusY="20" StrokeThickness="5" Fill="Transparent" />
    
          <!-- Inner Rectangle with rounded corners. -->
          <Rectangle x:Name="innerRectangle" HorizontalAlignment="Stretch"
            VerticalAlignment="Stretch" Stroke="Transparent"
            StrokeThickness="20"
            Fill="{TemplateBinding Background}" RadiusX="20" RadiusY="20"
          />
    
          <!-- Glass Rectangle -->
          <Rectangle x:Name="glassCube" HorizontalAlignment="Stretch"
            VerticalAlignment="Stretch"
            StrokeThickness="2" RadiusX="10" RadiusY="10" Opacity="0"
            Fill="{StaticResource MyGlassBrushResource}"
            RenderTransformOrigin="0.5,0.5">
            <Rectangle.Stroke>
              <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
                <LinearGradientBrush.GradientStops>
                  <GradientStop Offset="0.0" Color="LightBlue" />
                  <GradientStop Offset="1.0" Color="Gray" />
                </LinearGradientBrush.GradientStops>
              </LinearGradientBrush>
            </Rectangle.Stroke>
    
            <!-- These transforms have no effect as they
                 are declared here.
                 The reason the transforms are included is to be targets
                 for animation (see later). -->
            <Rectangle.RenderTransform>
              <TransformGroup>
                <ScaleTransform />
                <RotateTransform />
              </TransformGroup>
            </Rectangle.RenderTransform>
    
              <!-- A BevelBitmapEffect is applied to give the button a
                   "Beveled" look. -->
            <Rectangle.BitmapEffect>
              <BevelBitmapEffect />
            </Rectangle.BitmapEffect>
          </Rectangle>
    
          <!-- Present Text of the button. -->
          <DockPanel Name="myContentPresenterDockPanel">
            <ContentPresenter x:Name="myContentPresenter" Margin="20"
              Content="{TemplateBinding  Content}" TextBlock.Foreground="Black" />
          </DockPanel>
        </Grid>
    
        <ControlTemplate.Triggers>       <!-- Set action triggers for the buttons and define            what the button does in response to those triggers. -->     </ControlTemplate.Triggers>
      </ControlTemplate>
    </Setter.Value>
    
  2. Agregue desencadenadores de propiedad: Agregue el marcado resaltado al bloque ControlTemplate.Triggers:

    <ControlTemplate.Triggers>
    
      <!-- Set properties when mouse pointer is over the button. -->   <Trigger Property="IsMouseOver" Value="True">     <!-- Below are three property settings that occur when the           condition is met (user mouses over button).  -->     <!-- Change the color of the outer rectangle when user           mouses over it. -->     <Setter Property ="Rectangle.Stroke" TargetName="outerRectangle"       Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" />     <!-- Sets the glass opacity to 1, therefore, the           glass "appears" when user mouses over it. -->     <Setter Property="Rectangle.Opacity" Value="1" TargetName="glassCube" />     <!-- Makes the text slightly blurry as though you           were looking at it through blurry glass. -->     <Setter Property="ContentPresenter.BitmapEffect"        TargetName="myContentPresenter">       <Setter.Value>         <BlurBitmapEffect Radius="1" />       </Setter.Value>     </Setter>   </Trigger>
    
    <ControlTemplate.Triggers/>
    

    Presione F5 para ejecutar la aplicación y vea el efecto mientras pasa el puntero del mouse sobre los botones.

  3. Agregue un desencadenador de foco: A continuación, agregaremos algunos establecedores similares para controlar el caso cuando el botón tenga el foco (por ejemplo, después de que el usuario haga clic en él).

    <ControlTemplate.Triggers>
    
      <!-- Set properties when mouse pointer is over the button. -->
      <Trigger Property="IsMouseOver" Value="True">
    
        <!-- Below are three property settings that occur when the
             condition is met (user mouses over button).  -->
        <!-- Change the color of the outer rectangle when user          mouses over it. -->
        <Setter Property ="Rectangle.Stroke" TargetName="outerRectangle"
          Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" />
    
        <!-- Sets the glass opacity to 1, therefore, the          glass "appears" when user mouses over it. -->
        <Setter Property="Rectangle.Opacity" Value="1"       TargetName="glassCube" />
    
        <!-- Makes the text slightly blurry as though you were          looking at it through blurry glass. -->
        <Setter Property="ContentPresenter.BitmapEffect"       TargetName="myContentPresenter">
          <Setter.Value>
            <BlurBitmapEffect Radius="1" />
          </Setter.Value>
        </Setter>
      </Trigger>
      <!-- Set properties when button has focus. -->   <Trigger Property="IsFocused" Value="true">     <Setter Property="Rectangle.Opacity" Value="1"       TargetName="glassCube" />     <Setter Property="Rectangle.Stroke" TargetName="outerRectangle"       Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" />     <Setter Property="Rectangle.Opacity" Value="1" TargetName="glassCube" />   </Trigger>
    
    </ControlTemplate.Triggers>
    

    Presione F5 para ejecutar la aplicación y haga clic en uno de los botones. Observe que el botón permanece resaltado después de hacer clic en él porque sigue teniendo el foco. Si hace clic en otro botón, el nuevo botón obtiene el foco, mientras que el último lo pierde.

  4. Agregue animaciones paraMouseEnterYMouseLeave: A continuación, agregamos algunas animaciones a los desencadenadores. Agregue el siguiente marcado en cualquier parte del bloque ControlTemplate.Triggers.

    <!-- Animations that start when mouse enters and leaves button. -->
    <EventTrigger RoutedEvent="Mouse.MouseEnter">
      <EventTrigger.Actions>
        <BeginStoryboard Name="mouseEnterBeginStoryboard">
          <Storyboard>
          <!-- This animation makes the glass rectangle shrink in the X direction. -->
            <DoubleAnimation Storyboard.TargetName="glassCube"
              Storyboard.TargetProperty=
              "(Rectangle.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)"
              By="-0.1" Duration="0:0:0.5" />
            <!-- This animation makes the glass rectangle shrink in the Y direction. -->
            <DoubleAnimation
            Storyboard.TargetName="glassCube"
              Storyboard.TargetProperty=
              "(Rectangle.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)"
              By="-0.1" Duration="0:0:0.5" />
          </Storyboard>
        </BeginStoryboard>
      </EventTrigger.Actions>
    </EventTrigger>
    <EventTrigger RoutedEvent="Mouse.MouseLeave">
      <EventTrigger.Actions>
        <!-- Stopping the storyboard sets all animated properties back to default. -->
        <StopStoryboard BeginStoryboardName="mouseEnterBeginStoryboard" />
      </EventTrigger.Actions>
    </EventTrigger>
    

    El rectángulo de vidrio se reduce cuando el puntero del mouse se mueve sobre el botón y vuelve al tamaño normal cuando se saca el puntero.

    Hay dos animaciones que se desencadenan cuando el puntero pasa por encima del botón (se genera el evento MouseEnter). Estas animaciones reducen el rectángulo de vidrio a lo largo de los ejes X e Y. Observe las propiedades de los elementos DoubleAnimation, Duration y By. Duration especifica que la animación se produce más de medio segundo y By especifica que el vidrio se reduce en un 10 %.

    El segundo desencadenador de eventos (MouseLeave) simplemente detiene el primero. Cuando se detiene Storyboard, todas las propiedades animadas vuelven a sus valores predeterminados. Por lo tanto, cuando el usuario mueve el puntero fuera del botón, el botón vuelve a la forma en que estaba antes de que el puntero del mouse se moviera sobre él. Para obtener más información sobre animaciones, vea Información general sobre animaciones.

  5. Agregue una animación para cuando se haga clic en el botón: El último paso consiste en agregar un desencadenador para cuando el usuario hace clic en el botón. Agregue el siguiente marcado en cualquier parte del bloque ControlTemplate.Triggers:

    <!-- Animation fires when button is clicked, causing glass to spin.  -->
    <EventTrigger RoutedEvent="Button.Click">
      <EventTrigger.Actions>
        <BeginStoryboard>
          <Storyboard>
            <DoubleAnimation Storyboard.TargetName="glassCube"
              Storyboard.TargetProperty=
              "(Rectangle.RenderTransform).(TransformGroup.Children)[1].(RotateTransform.Angle)"
              By="360" Duration="0:0:0.5" />
          </Storyboard>
        </BeginStoryboard>
      </EventTrigger.Actions>
    </EventTrigger>
    

    Presione F5 para ejecutar la aplicación y haga clic en uno de los botones. Al hacer clic en un botón, el rectángulo de vidrio gira alrededor.

Resumen

En este tutorial, realizó los siguientes ejercicios:

  • Dirigió Style a un tipo de objeto (Button).

  • Controló las propiedades básicas de los botones de toda la aplicación mediante Style.

  • Creó recursos como degradados que se usarán para los valores de propiedad de los establecedores Style.

  • Personalizó la apariencia de los botones en toda la aplicación aplicándoles una plantilla.

  • Personalizó el comportamiento de los botones en respuesta a las acciones del usuario (como MouseEnter, MouseLeave y Click), que incluía efectos de animación.

Vea también