¿Cómo se cambia el fondo de un botón MouseOver en WPF?

93

Tengo un botón en mi página con este XAML:

<Button Content="Button" HorizontalAlignment="Left" VerticalAlignment="Bottom" 
    Width="50" Height="50" HorizontalContentAlignment="Left" 
    BorderBrush="{x:Null}" Foreground="{x:Null}" Margin="50,0,0,0">
    <Button.Style>
        <Style TargetType="Button">
            <Setter Property="Background" Value="Green"/>
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter Property="Background" Value="Red"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </Button.Style>
</Button>

Pero cuando coloco el mouse sobre mi botón, el fondo del botón cambia al fondo gris predeterminado de Windows.
¿Cuál es el problema?

Esta es la imagen del botón antes y después del mouseover:
Antes:
antes de
Después:
Después

Sepehr Mohammadi
fuente
Pero debe iniciar la imagen Forward-48.pngy activar IsMouseOver para cambiarla por la misma Forward-48.png. Estoy tratando de usar su código con diferentes imágenes y todo funcionó bien.
Anatoliy Nikolaev
1
@anatoliy: No funciona.
Sepehr Mohammadi
¿Después es tu color predeterminado? ¿En algún otro lugar no cambia / no establece un fondo de botón? Tengo tu código que funciona bien.
Anatoliy Nikolaev

Respuestas:

173

Para eliminar el MouseOvercomportamiento predeterminado en Button, deberá modificar el archivo ControlTemplate. Cambiar su Styledefinición a la siguiente debería funcionar:

<Style TargetType="{x:Type Button}">
    <Setter Property="Background" Value="Green"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Button}">
                <Border Background="{TemplateBinding Background}" BorderBrush="Black" BorderThickness="1">
                    <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Style.Triggers>
        <Trigger Property="IsMouseOver" Value="True">
            <Setter Property="Background" Value="Red"/>
        </Trigger>
    </Style.Triggers>
</Style>

EDITAR: Es unos años tarde, pero en realidad puede colocar el pincel de borde dentro del borde que está allí. No sé si se señaló eso, pero no parece que lo fuera ...

Richard E
fuente
1
Esto funciona, pero el botón Bordes desaparecerá. Tuve que poner un elemento <Border BorderBrush = "DarkGray" BorderThickness = "1"> alrededor del botón.
Venugopal M
4
@CF, la razón de esto es que el estilo de botón estándar tiene activadores dentro ControlTemplate, por lo que anulan los Styleactivadores de OP .
Torvin
1
@torvin ¡Eso parece tan al revés! ¿Por qué un activador definido por el usuario debe anularse por los predeterminados? Entiendo la jerarquía, ControlTemplate está por encima de Style, pero no entiendo por qué tiene que ser tan difícil anular configuraciones básicas como estas.
Fuselight
@Fuselight, el disparador dentro del ControlTemplatebásicamente dice 'Pinte el borde de acuerdo con el Backgroundcolor'. Y si el mouse está sobre el botón, pinte ese borde de este color en su lugar, mientras que en el estilo solo tiene acceso al Backgroundcolor, y no al color del borde subyacente. Sin embargo, veo que
apuntas
Esto tiene el beneficio adicional de eliminar el cuadro azul que aparece al pasar el mouse por encima, cuando se usa una imagen con un fondo transparente. En mi caso, no quería el borde, así que establezca BorderThickness en 0.
Chuck Savage
20

Todas las respuestas hasta ahora implican reemplazar completamente el comportamiento del botón predeterminado con algo más. Sin embargo, en mi humilde opinión, es útil e importante comprender que es posible cambiar solo la parte que le interesa , editando la plantilla predeterminada existente para un elemento XAML.

En el caso de tratar con el efecto de desplazamiento en un botón WPF, el cambio en la apariencia de un Buttonelemento WPF es causado por un Triggerestilo predeterminado para Button, que se basa en la IsMouseOverpropiedad y establece las propiedades Backgroundy BorderBrushdel Borderelemento de nivel superior en la plantilla de control. El Buttonfondo del elemento está debajo Borderdel fondo del elemento, por lo que cambiar la Button.Backgroundpropiedad no evita que se vea el efecto de desplazamiento.

Con un poco de esfuerzo, podría anular este comportamiento con su propio establecedor, pero debido a que el elemento que necesita afectar está en la plantilla y no se puede acceder directamente en su propio XAML, ese enfoque sería difícil y, en mi humilde opinión, demasiado complejo.

Otra opción sería utilizar el gráfico como Contentpara el en Buttonlugar de como Background. Si necesita contenido adicional sobre el gráfico, puede combinarlos con a Gridcomo objeto de nivel superior en el contenido.

Sin embargo, si literalmente solo desea deshabilitar el efecto de desplazamiento por completo (en lugar de solo ocultarlo), puede usar Visual Studio XAML Designer:

  1. Mientras editas tu XAML, selecciona la pestaña "Diseño" .
  2. En la pestaña "Diseño" , busque el botón para el que desea desactivar el efecto.
  3. Haga clic derecho en ese botón y seleccione "Editar plantilla / Editar una copia ..." . En el mensaje que aparece, seleccione dónde desea que se coloque el nuevo recurso de plantilla. Esto parecerá no hacer nada, pero de hecho el Diseñador habrá agregado nuevos recursos donde usted lo indicó y cambiado su elemento de botón para hacer referencia al estilo que usa esos recursos como la plantilla de botón.
  4. Ahora puedes editar ese estilo. Lo más fácil es eliminar o comentar (por ejemplo , Ctrl+ E, C) el <Trigger Property="IsMouseOver" Value="true">...</Trigger>elemento. Por supuesto, puede realizar cualquier cambio en la plantilla que desee en ese momento.

Cuando haya terminado, el estilo del botón se verá así:

<p:Style x:Key="FocusVisual">
  <Setter Property="Control.Template">
    <Setter.Value>
      <ControlTemplate>
        <Rectangle Margin="2" SnapsToDevicePixels="true" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2"/>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</p:Style>
<SolidColorBrush x:Key="Button.Static.Background" Color="#FFDDDDDD"/>
<SolidColorBrush x:Key="Button.Static.Border" Color="#FF707070"/>
<SolidColorBrush x:Key="Button.MouseOver.Background" Color="#FFBEE6FD"/>
<SolidColorBrush x:Key="Button.MouseOver.Border" Color="#FF3C7FB1"/>
<SolidColorBrush x:Key="Button.Pressed.Background" Color="#FFC4E5F6"/>
<SolidColorBrush x:Key="Button.Pressed.Border" Color="#FF2C628B"/>
<SolidColorBrush x:Key="Button.Disabled.Background" Color="#FFF4F4F4"/>
<SolidColorBrush x:Key="Button.Disabled.Border" Color="#FFADB2B5"/>
<SolidColorBrush x:Key="Button.Disabled.Foreground" Color="#FF838383"/>
<p:Style x:Key="ButtonStyle1" TargetType="{x:Type Button}">
  <Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}"/>
  <Setter Property="Background" Value="{StaticResource Button.Static.Background}"/>
  <Setter Property="BorderBrush" Value="{StaticResource Button.Static.Border}"/>
  <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
  <Setter Property="BorderThickness" Value="1"/>
  <Setter Property="HorizontalContentAlignment" Value="Center"/>
  <Setter Property="VerticalContentAlignment" Value="Center"/>
  <Setter Property="Padding" Value="1"/>
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type Button}">
        <Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="true">
          <ContentPresenter x:Name="contentPresenter" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
        </Border>
        <ControlTemplate.Triggers>
          <Trigger Property="IsDefaulted" Value="true">
            <Setter Property="BorderBrush" TargetName="border" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
          </Trigger>
          <!--<Trigger Property="IsMouseOver" Value="true">
            <Setter Property="Background" TargetName="border" Value="{StaticResource Button.MouseOver.Background}"/>
            <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.MouseOver.Border}"/>
          </Trigger>-->
          <Trigger Property="IsPressed" Value="true">
            <Setter Property="Background" TargetName="border" Value="{StaticResource Button.Pressed.Background}"/>
            <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.Pressed.Border}"/>
          </Trigger>
          <Trigger Property="IsEnabled" Value="false">
            <Setter Property="Background" TargetName="border" Value="{StaticResource Button.Disabled.Background}"/>
            <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.Disabled.Border}"/>
            <Setter Property="TextElement.Foreground" TargetName="contentPresenter" Value="{StaticResource Button.Disabled.Foreground}"/>
          </Trigger>
        </ControlTemplate.Triggers>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</p:Style>

(Nota: puede omitir las p:calificaciones del espacio de nombres XML en el código real ... Las proporciono aquí solo porque el formateador de código XML de Stack Overflow se confunde con <Style/>elementos que no tienen un nombre completo con el espacio de nombres XML).

Si desea aplicar el mismo estilo a otros botones, puede simplemente hacer clic derecho en ellos y elegir "Editar plantilla / Aplicar recurso" y seleccionar el estilo que acaba de agregar para el primer botón. Incluso puede hacer que ese estilo sea el estilo predeterminado para todos los botones, utilizando las técnicas normales para aplicar un estilo predeterminado a los elementos en XAML.

Peter Duniho
fuente
5
Muchas gracias. Esta es la única respuesta tolerable aquí
Jared Beach
13

Esto funcionó bien para mí.

Estilo de botón

<Style x:Key="TransparentStyle" TargetType="{x:Type Button}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <Border>
                    <Border.Style>
                        <Style TargetType="{x:Type Border}">
                            <Style.Triggers>
                                <Trigger Property="IsMouseOver" Value="True">
                                    <Setter Property="Background" Value="DarkGoldenrod"/>
                                </Trigger>
                            </Style.Triggers>
                        </Style>
                    </Border.Style>
                    <Grid Background="Transparent">
                        <ContentPresenter></ContentPresenter>
                    </Grid>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Botón

<Button Style="{StaticResource TransparentStyle}" VerticalAlignment="Top" HorizontalAlignment="Right" Width="25" Height="25"
        Command="{Binding CloseWindow}">
    <Button.Content >
        <Grid Margin="0 0 0 0">
            <Path Data="M0,7 L10,17 M0,17 L10,7" Stroke="Blue" StrokeThickness="2" HorizontalAlignment="Center" Stretch="None" />
        </Grid>
    </Button.Content>
</Button>

Notas

  • El botón muestra una pequeña cruz azul, muy parecida a la que se usa para cerrar una ventana.
  • Al establecer el fondo de la cuadrícula en "Transparente", agrega un hittest, lo que significa que si el mouse está en cualquier lugar sobre el botón, entonces funcionará. Omita esta etiqueta y el botón solo se iluminará si el mouse está sobre una de las líneas vectoriales en el ícono (esto no es muy útil).
Aplazamiento de pago
fuente
1
Esta es una gran respuesta, pero ¿qué pasa con cambiar el Strokecolor al pasar el Bordermouse también, sin que solo se sitúe sobre el Path?
Nateous
1
Esta x:Key="TransparentStyle"parte y el uso fueron importantes para mí para llegar allí ... ¡Gracias!
nrod
6

Solo quiero compartir mi estilo de botón de mi ResourceDictionary que he estado usando. Puede cambiar libremente el fondo de onHover en los activadores de estilo. " ColorAnimation To = * su BG deseado (es decir, # FFCEF7A0)". El BG del botón también volverá automáticamente a su BG original después del estado mouseOver. Incluso puede configurar la velocidad de la transición.

Diccionario de recursos

<Style x:Key="Flat_Button" TargetType="{x:Type Button}">
    <Setter Property="Width" Value="100"/>
    <Setter Property="Height" Value="50"/>
    <Setter Property="Margin" Value="2"/>
    <Setter Property="FontFamily" Value="Arial Narrow"/>
    <Setter Property="FontSize" Value="12px"/>
    <Setter Property="FontWeight" Value="Bold"/>
    <Setter Property="Cursor" Value="Hand"/>
    <Setter Property="Foreground">
        <Setter.Value>
            <SolidColorBrush Opacity="1" Color="White"/>
        </Setter.Value>
    </Setter>
    <Setter Property="Background" >
        <Setter.Value>
            <SolidColorBrush Opacity="1" Color="#28C2FF" />
        </Setter.Value>
    </Setter>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Button}">

                <Border x:Name="border"
                         SnapsToDevicePixels="True"
                         BorderThickness="1"
                         Padding="4,2"
                         BorderBrush="Gray"
                         CornerRadius="3"
                         Background="{TemplateBinding Background}">
                    <Grid>
                        <ContentPresenter 
                        Margin="2"
                        HorizontalAlignment="Center"
                        VerticalAlignment="Center"
                        RecognizesAccessKey="True" />

                    </Grid>
                </Border>

            </ControlTemplate>
        </Setter.Value>
    </Setter>

    <Style.Triggers>
        <Trigger Property="IsMouseOver" Value="true">
            <Trigger.EnterActions>
                <BeginStoryboard>
                    <Storyboard>
                        <ColorAnimation To="#D2F898"
                                        Storyboard.TargetProperty="(Control.Background).(SolidColorBrush.Color)" 
                                        FillBehavior="HoldEnd" Duration="0:0:0.25" AutoReverse="False" RepeatBehavior="1x"/>
                    </Storyboard>
                </BeginStoryboard>
            </Trigger.EnterActions>

            <Trigger.ExitActions>
                <BeginStoryboard>
                    <Storyboard>
                        <ColorAnimation
                                            Storyboard.TargetProperty="(Control.Background).(SolidColorBrush.Color)" 
                                            FillBehavior="HoldEnd" Duration="0:0:0.25" AutoReverse="False" RepeatBehavior="1x"/>
                    </Storyboard>
                </BeginStoryboard>
            </Trigger.ExitActions>

        </Trigger>


    </Style.Triggers>
</Style>

todo lo que tienes que hacer es llamar al estilo.

Implementación de ejemplo

<Button Style="{StaticResource Flat_Button}" Height="Auto"Width="Auto">  
     <StackPanel>
     <TextBlock Text="SAVE" FontFamily="Arial" FontSize="10.667"/>
     </StackPanel>
</Button>
Justin Adrias
fuente
2

Una respuesta un poco más difícil que usa ControlTemplate y tiene un efecto de animación (adaptado de https://docs.microsoft.com/en-us/dotnet/framework/wpf/controls/customizing-the-appearance-of-an-existing- control )

En su diccionario de recursos, defina una plantilla de control para su botón como esta:

<ControlTemplate TargetType="Button" x:Key="testButtonTemplate2">
    <Border Name="RootElement">
        <Border.Background>
            <SolidColorBrush x:Name="BorderBrush" Color="Black"/>
        </Border.Background>

        <Grid Margin="4" >
            <Grid.Background>
                <SolidColorBrush x:Name="ButtonBackground" Color="Aquamarine"/>
            </Grid.Background>
            <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Margin="4,5,4,4"/>
        </Grid>
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="CommonStates">
                <VisualState x:Name="Normal"/>
                <VisualState x:Name="MouseOver">
                    <Storyboard>
                        <ColorAnimation Storyboard.TargetName="ButtonBackground" Storyboard.TargetProperty="Color" To="Red"/>
                    </Storyboard>
                </VisualState>
                <VisualState x:Name="Pressed">
                    <Storyboard>
                        <ColorAnimation Storyboard.TargetName="ButtonBackground" Storyboard.TargetProperty="Color" To="Red"/>
                    </Storyboard>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
    </Border>
</ControlTemplate>

en su XAML puede usar la plantilla de arriba para su botón de la siguiente manera:

Define tu botón

<Button Template="{StaticResource testButtonTemplate2}" 
HorizontalAlignment="Center" VerticalAlignment="Center" 
Foreground="White">My button</Button>

Espero eso ayude

Iakobos Karakizas
fuente
0

Para cambiar el estilo del botón

Primero: definir estilos de recursos

<Window.Resources>

    <Style x:Key="OvergroundIn" TargetType="Button">

        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <Grid Background="#FF16832F">
                        <ContentPresenter TextBlock.Foreground="White" TextBlock.TextAlignment="Center" Margin="0,8,0,0" ></ContentPresenter>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>

        <Style.Triggers>
            <Trigger Property="IsMouseOver" Value="True">

                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="Button">
                            <Grid Background="#FF06731F">
                                <ContentPresenter TextBlock.Foreground="White" TextBlock.TextAlignment="Center" Margin="0,8,0,0" ></ContentPresenter>
                            </Grid>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>

            </Trigger>
        </Style.Triggers>

    </Style>

    <Style x:Key="OvergroundOut" TargetType="Button">

        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <Grid Background="#FFF35E5E">
                        <ContentPresenter TextBlock.Foreground="White" TextBlock.TextAlignment="Center" Margin="0,8,0,0" ></ContentPresenter>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>

        <Style.Triggers>
            <Trigger Property="IsMouseOver" Value="True">

                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="Button">
                            <Grid Background="#FFE34E4E">
                                <ContentPresenter TextBlock.Foreground="White" TextBlock.TextAlignment="Center" Margin="0,8,0,0" ></ContentPresenter>
                            </Grid>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>

            </Trigger>
        </Style.Triggers>

    </Style>


</Window.Resources>

2do código de botón definido

                           <Border Grid.Column="2" BorderBrush="LightGray" BorderThickness="2" CornerRadius="3" Margin="2,2,2,2"  >
                                <Button Name="btnFichar" BorderThickness="0" Click="BtnFichar_Click">
                                    <Button.Content>
                                        <Grid>
                                            <TextBlock Margin="0,7,0,7" TextAlignment="Center">Fichar</TextBlock> 
                                        </Grid>
                                    </Button.Content>
                                </Button>
                            </Border>

3er código detrás

    public void ShowStatus()
    {
        switch (((MainDto)this.DataContext).State)
        {
            case State.IN:
                this.btnFichar.BorderBrush = new SolidColorBrush(Color.FromRgb(243, 94, 94));
                this.btnFichar.Style = Resources["OvergroundIn"] as Style;
                this.btnFichar.Content = "Fichar Salida";
                break;

            case State.OUT:
                this.btnFichar.BorderBrush = new SolidColorBrush(Color.FromRgb(76, 106, 83));
                this.btnFichar.Style = Resources["OvergroundOut"] as Style;
                this.btnFichar.Content = "Fichar Entrada";
                break;

        }
    }
Ángel Ibáñez
fuente