Como você altera o plano de fundo de um botão MouseOver no WPF?

93

Tenho um botão na minha página com 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>

Mas quando coloco o mouse sobre o botão, o plano de fundo do botão muda para o plano de fundo cinza padrão do Windows.
Qual é o problema?

Esta é a imagem do botão antes e depois do mouseover:
Antes:
Antes
Depois:
Depois de

Sepehr Mohammadi
fonte
Mas você tem que iniciar a imagem Forward-48.pnge acionar o IsMouseOver para alterá-la da mesma forma Forward-48.png. Estou tentando usar o seu código com imagens diferentes e tudo funcionou bem.
Anatoliy Nikolaev
1
@anatoliy: Não funciona.
Sepehr Mohammadi
Depois é a sua cor padrão? Em qualquer outro lugar você não altera / não define um fundo de botão? Eu tenho seu código funciona bem.
Anatoliy Nikolaev

Respostas:

173

Para remover o MouseOvercomportamento padrão do, Buttonvocê precisará modificar o ControlTemplate. Mudar sua Styledefinição para o seguinte deve resolver o problema:

<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>

EDIT: Está alguns anos atrasado, mas você é realmente capaz de definir o pincel de borda dentro da borda que está lá. Idk se isso foi apontado, mas não parece que foi ...

Richard E
fonte
1
Isso funciona, porém o botão Bordas desaparecerá! Tive que colocar um elemento <Border BorderBrush = "DarkGray" BorderThickness = "1"> ao redor do botão.
Venugopal M
4
@CF a razão para isso é que o estilo Botão padrão tem gatilhos internos ControlTemplate, então eles substituem os Stylegatilhos do OP .
torvin
1
@torvin Isso parece tão atrasado! Por que um gatilho definido pelo usuário deve ser substituído pelos padrões? Eu entendo a hierarquia, ControlTemplate está acima de Style, mas não entendo por que deve ser tão difícil substituir configurações básicas como essas.
Fuselight
@Fuselight, o gatilho dentro do ControlTemplatediz basicamente 'Pinte a borda de acordo com a Backgroundcor. E se o mouse estiver sobre o botão - pinte essa borda com esta cor, enquanto no estilo você só tem acesso à Backgroundcor, e não à cor da borda subjacente. Vejo você apontar, porém, o estilo WPF deixa muito a desejar ...
torvin
Isso tem o benefício adicional de remover a caixa azul que aparece no rollover, ao usar uma imagem com um fundo transparente. No meu caso, eu não queria a borda, então defina BorderThickness como 0.
Chuck Savage
20

Todas as respostas até agora envolvem a substituição completa do comportamento do botão padrão por outra coisa. No entanto, IMHO é útil e importante entender que é possível alterar apenas a parte de seu interesse , editando o modelo padrão existente para um elemento XAML.

No caso de lidar com o efeito de foco em um botão WPF, a mudança na aparência em um Buttonelemento WPF é causada por um Triggerno estilo padrão de Button, que é baseado na IsMouseOverpropriedade e define as propriedades Backgrounde BorderBrushdo Borderelemento de nível superior no modelo de controle. O Buttonplano de fundo do elemento está abaixo Borderdo plano de fundo do elemento, portanto, alterar a Button.Backgroundpropriedade não impede que o efeito de foco seja visto.

Com algum esforço, você pode substituir esse comportamento por seu próprio configurador, mas como o elemento que você precisa afetar está no modelo e não está diretamente acessível em seu próprio XAML, essa abordagem seria difícil e IMHO excessivamente complexa.

Outra opção seria usar o gráfico como Contentpara o em Buttonvez de Background. Se precisar de conteúdo adicional sobre o gráfico, você pode combiná-los com um Gridcomo o objeto de nível superior no conteúdo.

No entanto, se você literalmente quiser apenas desabilitar totalmente o efeito de foco (em vez de apenas ocultá-lo), você pode usar o Visual Studio XAML Designer:

  1. Ao editar seu XAML, selecione a guia "Design" .
  2. Na guia "Design" , encontre o botão para o qual deseja desativar o efeito.
  3. Clique com o botão direito nesse botão e escolha "Editar modelo / Editar uma cópia ..." . Selecione no prompt que você obtém onde deseja que o novo recurso de modelo seja colocado. Isso parecerá não fazer nada, mas na verdade o Designer terá adicionado novos recursos onde você disse e alterado o elemento do botão para fazer referência ao estilo que usa esses recursos como o modelo do botão.
  4. Agora, você pode editar esse estilo. A coisa mais fácil é excluir ou comentar (por exemplo , Ctrl+ E, C) o <Trigger Property="IsMouseOver" Value="true">...</Trigger>elemento. Claro, você pode fazer qualquer alteração no modelo que desejar nesse ponto.

Quando terminar, o estilo do botão será mais ou menos assim:

<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>

(Observação: você pode omitir as p:qualificações de namespace XML no código real ... Eu as forneço aqui apenas porque o formatador de código Stack Overflow XML fica confuso com <Style/>elementos que não têm um nome totalmente qualificado com namespace XML.)

Se você quiser aplicar o mesmo estilo a outros botões, basta clicar com o botão direito neles e escolher "Editar modelo / Aplicar recurso" e selecionar o estilo que acabou de adicionar para o primeiro botão. Você pode até tornar esse estilo o estilo padrão para todos os botões, usando as técnicas normais para aplicar um estilo padrão a elementos em XAML.

Peter Duniho
fonte
5
Muito obrigado. Esta é a única resposta tolerável aqui
Jared Beach
13

Isto funcionou bem para mim.

Estilo de Botão

<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ão

<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

  • O botão exibe uma pequena cruz azul, muito parecida com a usada para fechar uma janela.
  • Ao definir o fundo da grade para "Transparente", ele adiciona um toque, o que significa que se o mouse estiver em qualquer lugar sobre o botão, ele funcionará. Omita esta tag, e o botão só acenderá se o mouse estiver sobre uma das linhas do vetor no ícone (isso não é muito utilizável).
Contango
fonte
1
Essa é uma ótima resposta, mas que tal mudar a Strokecor ao passar o mouse sobre o Bordertambém, sem que ele apenas passe o mouse sobre o Path?
Nateous
1
Essa x:Key="TransparentStyle"parte e o uso foram importantes para eu chegar lá ... Obrigado!
nrod
6

Só quero compartilhar o estilo do meu botão do ResourceDictionary que tenho usado. Você pode alterar livremente o plano de fundo onHover nos gatilhos de estilo. " ColorAnimation To = * seu BG desejado (ou seja, # FFCEF7A0)". O botão BG também reverterá automaticamente ao seu BG original após o estado mouseOver. Você pode até definir a velocidade da transição.

Dicionário 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>

tudo que você precisa fazer é chamar o estilo.

Exemplo de implementação

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

Uma resposta um pouco mais difícil que usa ControlTemplate e tem um efeito de animação (adaptado de https://docs.microsoft.com/en-us/dotnet/framework/wpf/controls/customizing-the-appearance-of-an-existing- controle )

Em seu dicionário de recursos, defina um modelo de controle para seu botão como este:

<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>

em seu XAML, você pode usar o modelo acima para o botão conforme abaixo:

Defina o seu botão

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

Espero que ajude

Iakobos Karakizas
fonte
0

Para alterar o estilo do botão

1º: 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>

2º definir o código do botão

                           <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>

3º código atrá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
fonte