2010-12-12 13 views
9

Por lo tanto, el deseo es simple, cambie el fondo de un botón a Verde claro, Verde cuando el cursor del mouse se cierne sobre él y Verde oscuro cuando se presiona. El siguiente XAML es mi primer intento:Anulación de fondo de botón en WPF en Aero

<Window x:Class="ButtonMouseOver.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="350" Width="525"> 
    <Grid> 
    <Button Background="LightGreen"> 
     Hello 
     <Button.Style> 
     <Style TargetType="Button"> 
      <Style.Triggers> 
      <Trigger Property="IsMouseOver" Value="true"> 
       <Setter Property = "Background" Value="Green"/> 
      </Trigger> 
      <Trigger Property="IsPressed" Value="true"> 
       <Setter Property = "Foreground" Value="DarkGreen"/> 
      </Trigger> 
      </Style.Triggers> 
     </Style> 
     </Button.Style> 
    </Button> 
    </Grid> 
</Window> 

Pero, ¡ay !, esto no funciona. Estamos a solo 1/3 del camino hacia la meta. Sí, el botón se vuelve verde claro, pero tan pronto como pasas el cursor sobre él o lo presionas, obtienes Aero Chrome estándar para los respectivos estados de los botones. No querer renunciar, intento el siguiente libertinaje:

... 
    <Button xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero" 
      Background="LightGreen"> 
     Hello 
     <Button.Template> 
     <ControlTemplate TargetType="{x:Type Button}"> 
      <Microsoft_Windows_Themes:ButtonChrome SnapsToDevicePixels="true" 
      x:Name="Chrome" Background="{TemplateBinding Background}" 
      BorderBrush="{TemplateBinding BorderBrush}" RenderDefaulted="{TemplateBinding IsDefaulted}" 
      RenderMouseOver="{TemplateBinding IsMouseOver}" RenderPressed="{TemplateBinding IsPressed}" 
      > 
      <ContentPresenter Margin="{TemplateBinding Padding}" 
              VerticalAlignment="{TemplateBinding VerticalContentAlignment}" 
              HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
              RecognizesAccessKey="True" 
              SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/> 
      </Microsoft_Windows_Themes:ButtonChrome> 
     </ControlTemplate> 
     </Button.Template> 
     <Button.Style> 
     <Style TargetType="Button"> 
      <Style.Triggers> 
      <Trigger Property="IsMouseOver" Value="true"> 
       <Setter Property = "Background" Value="Green"/> 
      </Trigger> 
      <Trigger Property="IsPressed" Value="true"> 
       <Setter Property = "Foreground" Value="DarkGreen"/> 
      </Trigger> 
      </Style.Triggers> 
     </Style> 
     </Button.Style> 
    </Button> 
... 

ahora tenemos toda la plantilla de control puto tirado ahí levantado de Aero.NormalColor.xaml. Por desgracia, esto no cambia nada. Luego voy a eliminar dos atributos (RenderPressed y RenderMouseOver) del elemento Microsoft_Windows_Themes:ButtonChrome. Aún así, no hay cambio. entonces quitar la configuración del atributo del botón Background, dejando sólo la declaración de espacio para el montaje PresentationFramework.Aero:

... 
<Button xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"> 
    Hello 
... 

Por último, tenemos el progreso. Hemos pasado de 1/3 de los requisitos a 2/3 del camino, con IsMouseOver e IsPressed en funcionamiento, pero sin fondo verde claro durante el estado normal del botón (de no estar sobre moused o presionado), ya que eliminé la propiedad de fondo del botón, para que los otros dos estados se apliquen y sean visibles. Ahora, después de este XAML maníaca no llevarnos el fondo verde claro para el estado normal de los botones, modifico el estilo de lanzar el color de fondo en allí también:

<Button xmlns... 
    <ControlTemplate... 
    ... 
    </ControlTemplate> 
    <Button.Style> 
     <Style TargetType="Button"> 
     <!-- ##### Normal state button background added ##### --> 
     <Setter Property="Background" Value="LightGreen" /> 
     <!-- ################################################ --> 
     <Style.Triggers> 
      <Trigger Property="IsMouseOver" Value="true"> 
      <Setter Property = "Background" Value="Green"/> 
      </Trigger> 
      <Trigger Property="IsPressed" Value="true"> 
      <Setter Property = "Background" Value="DarkGreen"/> 
      </Trigger> 
     </Style.Triggers> 
     </Style> 
    </Button.Style> 
    </Button> 

Por último, funciona según lo previsto.

¿Estoy loco, o son estos (y más) los aros que tiene que pasar con un tema Aero para simplemente cambiar el color de fondo de un botón en algunos de sus diversos estados (normal, suspendido, presionado)? Tal vez, la vida no sería tan mala si no tuviera que incluir todo el Dang ButtonTemplate allí solo para eliminar los dos atributos (RenderMouseOver y RenderPressed) de él.

Gracias por cualquier ayuda. Estoy en el final.

Actualización: Pero espere, hay más de esto. En lugar de eliminar la RenderMouseOver y atributos RenderPressed de la plantilla de control, simplemente cambiando desde:

<Microsoft_Windows_Themes:ButtonChrome SnapsToDevicePixels="true" ... 
    RenderMouseOver="{TemplateBinding IsMouseOver}" 
    RenderPressed="{TemplateBinding IsPressed}" ... 

a:

<Microsoft_Windows_Themes:ButtonChrome SnapsToDevicePixels="true" ... 
    RenderMouseOver="{Binding IsMouseOver}" 
    RenderPressed="{Binding IsPressed}" ... 

..., también soluciona el problema (de ignorar el estilo del botón activa) . Creo que la raíz del problema es que los enlaces de plantilla se aplican en tiempo de compilación (por razones de rendimiento), mientras que los enlaces regulares se aplican en tiempo de ejecución. Debido a esto, las vinculaciones de los activadores de estilo de los botones individuales no se utilizan si los atributos usan enlaces de plantilla (es decir, se usan en su lugar IsMouseOver e IsPressed de la plantilla original).

Habiendo dicho todo lo anterior, aquí está el ejemplo canónico para cambiar el fondo de un botón en Aero, manteniendo su plantilla de control original:

<Window x:Class="ButtonMouseOver.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="350" Width="525"> 
    <Grid> 
    <Button> 
     Hello 
     <Button.Template> 
     <ControlTemplate TargetType="{x:Type Button}"> 
      <Microsoft_Windows_Themes:ButtonChrome SnapsToDevicePixels="true" 
      x:Name="Chrome" Background="{TemplateBinding Background}" 
      BorderBrush="{TemplateBinding BorderBrush}" RenderDefaulted="{TemplateBinding IsDefaulted}" 
      RenderMouseOver="{Binding IsMouseOver}" RenderPressed="{Binding IsPressed}" 
      > 
      <ContentPresenter Margin="{TemplateBinding Padding}" 
              VerticalAlignment="{TemplateBinding VerticalContentAlignment}" 
              HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
              RecognizesAccessKey="True" 
              SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/> 
      </Microsoft_Windows_Themes:ButtonChrome> 
     </ControlTemplate> 
     </Button.Template> 
     <Button.Style> 
     <Style TargetType="Button"> 
      <Setter Property="Background" Value="LightGreen"/> 
      <Style.Triggers> 
      <Trigger Property="IsMouseOver" Value="true"> 
       <Setter Property = "Background" Value="Green"/> 
      </Trigger> 
      <Trigger Property="IsPressed" Value="true"> 
       <Setter Property = "Foreground" Value="DarkGreen"/> 
      </Trigger> 
      </Style.Triggers> 
     </Style> 
     </Button.Style> 
    </Button> 
    </Grid> 
</Window> 

Esto es, por supuesto, asumiendo que un solo botón es tan labrado, de lo contrario, la plantilla y el estilo se pueden mover a una sección de recursos en algún lugar. Además, no existe un disparador para el estado predeterminado de un botón, pero se agrega fácilmente al ejemplo anterior (no olvide cambiar el atributo RenderDefaulted en la plantilla de control para usar Binding en lugar de TemplateBinding).

Si alguien tiene alguna sugerencia sobre cómo anulación la TemplateBinding con la unión de sólo los dos atributos en la plantilla de control que tienen que cambiar, sin repetir la definición completa del cromo de la venta al por mayor aerodinámica xaml, soy todo oídos.

Respuesta

2

La plantilla predeterminada para Button utiliza un ButtonChrome, que realiza su propio dibujo. Si desea deshacerse por completo de la apariencia predeterminada, debe definir su propia plantilla, sin el ButtonChrome. Sé que suena tedioso, pero solo tienes que hacerlo una vez: puedes poner tu estilo personalizado en un diccionario de recursos, y solo consultarlo con StaticResource. Tenga en cuenta que también puede aplicar el estilo a todos los botones de su aplicación utilizando {x:Type Button} como la clave del estilo (x:Key atributo)

+0

El problema es que solo quiero cambiar el fondo de un botón. AeroCrome lo maneja correctamente utilizando el atributo de botón de fondo para el estado normal del botón. Pero este manejo es defectuoso, porque el fondo cambia inmediatamente al pasar el mouse y cuando se presiona el botón. Aparentemente, no hay una manera fácil de cambiar el fondo del botón en esos dos estados. Esto derrota el propósito total de tener un atributo de fondo en el botón (y tal vez en otros elementos visuales). –

+0

La propiedad Background es común a todos los controles, por lo que estará allí de todos modos, pero nada garantiza que la plantilla lo tendrá en cuenta. Puedo reproducir su problema con el tema Aero y un problema similar con el tema Luna. Parece que ButtonChrome no tiene en cuenta el fondo para ciertos estados ... De todos modos, no creo que el botón estándar Chrome esté diseñado para personalizar sus colores. Si quieres hacer eso, simplemente no uses el cromo ... De todos modos, es bastante fácil crear tu propia plantilla de botones sin ella. –

+0

Desde MSDN (propiedad Control.Background): la propiedad de fondo se aplica solo al estado de reposo de un control. El estilo predeterminado del control especifica su apariencia cuando cambia el estado del control. Por ejemplo, si configura la propiedad de Fondo en un Botón, el botón tiene ese valor solo cuando no está presionado o deshabilitado. Si desea crear un control que tenga una personalización más avanzada del fondo, debe definir el estilo del control. –

Cuestiones relacionadas