Comment modifier l'arrière-plan d'un bouton MouseOver dans WPF?

93

J'ai un bouton sur ma page avec ce 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>

Mais lorsque je place la souris sur mon bouton, l'arrière-plan du bouton change en arrière-plan gris par défaut.
Quel est le problème?

Voici l'image du bouton avant et après le survol de la souris:
Avant:
Avant
Après:
Après

Sepehr Mohammadi
la source
Mais vous devez démarrer l'image Forward-48.pnget déclencher IsMouseOver pour la changer pour la même chose Forward-48.png. J'essaie d'utiliser votre code avec différentes images et j'ai tout bien fonctionné.
Anatoliy Nikolaev
1
@anatoliy: ça ne marche pas.
Sepehr Mohammadi
Après est votre couleur par défaut? Ailleurs, vous ne modifiez pas / ne définissez pas l'arrière-plan d'un bouton? J'ai votre code fonctionne bien.
Anatoliy Nikolaev

Réponses:

173

Pour supprimer le MouseOvercomportement par défaut sur le, Buttonvous devrez modifier le ControlTemplate. Changer votre Styledéfinition comme suit devrait faire l'affaire:

<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: Il y a quelques années de retard, mais vous pouvez en fait définir le pinceau de bordure à l'intérieur de la bordure qui s'y trouve. Idk si cela a été signalé mais il ne semble pas que ce soit le cas ...

Richard E
la source
1
Cela fonctionne, mais le bouton Bordures disparaîtra! J'ai dû mettre un élément <Border BorderBrush = "DarkGray" BorderThickness = "1"> autour du bouton.
Venugopal M
4
@CF la raison en est que le style Button standard a des déclencheurs à l'intérieur ControlTemplate, donc ils remplacent les Styledéclencheurs d'OP .
torvin
1
@torvin Cela semble tellement à l'envers! Pourquoi un déclencheur défini par l'utilisateur devrait-il être remplacé par ceux par défaut? Je comprends la hiérarchie, ControlTemplate est au-dessus de Style, mais je ne comprends pas pourquoi il doit être si difficile de remplacer des paramètres de base comme ceux-ci.
Fuselight
@Fuselight, le déclencheur à l'intérieur du ControlTemplatedit essentiellement «Peignez la bordure en fonction de la Backgroundcouleur. Et si la souris est au-dessus du bouton - peignez cette bordure de cette couleur à la place, alors que dans le style, vous n'avez accès qu'à la Backgroundcouleur, et non à la couleur de bordure sous-jacente. Je vois que vous faites remarquer cependant, le style WPF laisse beaucoup à désirer ...
torvin
Cela présente l'avantage supplémentaire de supprimer la boîte bleue qui apparaît lors du survol, lorsque vous utilisez une image avec un arrière-plan transparent. Dans mon cas, je ne voulais pas de bordure, alors réglez BorderThickness à 0.
Chuck Savage
20

Toutes les réponses jusqu'à présent impliquent de remplacer complètement le comportement par défaut du bouton par autre chose. Cependant, à mon humble avis, il est utile et important de comprendre qu'il est possible de changer uniquement la partie qui vous intéresse , en modifiant le modèle par défaut existant pour un élément XAML.

Dans le cas de la gestion de l'effet de survol sur un bouton WPF, le changement d'apparence dans un Buttonélément WPF est causé par un Triggerdans le style par défaut pour le Button, qui est basé sur la IsMouseOverpropriété et définit les propriétés Backgroundet BorderBrushde l' Borderélément de niveau supérieur dans le modèle de contrôle. L' Buttonarrière-plan de l' Borderélément est sous l'arrière-plan de l' élément, donc la modification de la Button.Backgroundpropriété n'empêche pas l'effet de survol d'être vu.

Avec un peu d'effort, vous pouvez remplacer ce comportement avec votre propre setter, mais comme l'élément que vous devez affecter est dans le modèle et n'est pas directement accessible dans votre propre XAML, cette approche serait difficile et à mon humble avis trop complexe.

Une autre option serait d'utiliser le graphique comme Contentpour le Buttonplutôt que pour le Background. Si vous avez besoin de contenu supplémentaire sur le graphique, vous pouvez les combiner avec un Gridcomme objet de niveau supérieur dans le contenu.

Cependant, si vous souhaitez littéralement désactiver complètement l'effet de survol (plutôt que simplement le masquer), vous pouvez utiliser le concepteur Visual Studio XAML:

  1. Lors de la modification de votre XAML, sélectionnez l' onglet "Conception" .
  2. Dans l' onglet "Conception" , recherchez le bouton dont vous souhaitez désactiver l'effet.
  3. Cliquez avec le bouton droit sur ce bouton et choisissez "Modifier le modèle / Modifier une copie ..." . Sélectionnez dans l'invite que vous obtenez où vous voulez que la nouvelle ressource de modèle soit placée. Cela semblera ne rien faire, mais en fait, le concepteur aura ajouté de nouvelles ressources là où vous l'avez indiqué et modifié votre élément de bouton pour référencer le style qui utilise ces ressources comme modèle de bouton.
  4. Maintenant, vous pouvez modifier ce style. Le plus simple est de supprimer ou de commenter (par exemple Ctrl+ E, C) l' <Trigger Property="IsMouseOver" Value="true">...</Trigger>élément. Bien entendu, vous pouvez apporter les modifications souhaitées au modèle à ce stade.

Lorsque vous avez terminé, le style du bouton ressemblera à ceci:

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

(Remarque: vous pouvez omettre les p:qualifications d'espace de noms XML dans le code réel ... Je les fournis ici uniquement parce que le formateur de code XML de Stack Overflow est confondu par des <Style/>éléments qui n'ont pas de nom complet avec un espace de noms XML.)

Si vous souhaitez appliquer le même style à d'autres boutons, vous pouvez simplement cliquer dessus avec le bouton droit de la souris et choisir "Modifier le modèle / Appliquer la ressource" et sélectionner le style que vous venez d'ajouter pour le premier bouton. Vous pouvez même faire de ce style le style par défaut pour tous les boutons, en utilisant les techniques normales pour appliquer un style par défaut aux éléments en XAML.

Peter Duniho
la source
5
Merci beaucoup. C'est la seule réponse tolérable ici
Jared Beach
13

Cela a bien fonctionné pour moi.

Style de bouton

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

Bouton

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

Remarques

  • Le bouton affiche une petite croix bleue, un peu comme celle utilisée pour fermer une fenêtre.
  • En définissant l'arrière-plan de la grille sur "Transparent", il ajoute un hittest, ce qui signifie que si la souris est n'importe où sur le bouton, alors cela fonctionnera. Omettez cette balise, et le bouton ne s'allumera que si la souris est sur l'une des lignes vectorielles de l'icône (ce n'est pas très utilisable).
Contango
la source
1
C'est une excellente réponse, mais qu'en est-il également de changer la Strokecouleur en Bordersurvolant le, sans qu'il ne survole uniquement le Path?
Nateous
1
Cette x:Key="TransparentStyle"partie et l'utilisation étaient importantes pour moi pour y arriver ... Merci!
nrod le
6

Je veux juste partager mon style de bouton de mon ResourceDictionary que j'utilise. Vous pouvez modifier librement l'arrière-plan onHover au niveau des déclencheurs de style. " ColorAnimation To = * votre BG souhaité (c'est-à-dire # FFCEF7A0)". Le bouton BG reviendra également automatiquement à sa BG d'origine après l'état mouseOver.Vous pouvez même définir la vitesse de transition.

Dictionnaire des ressources

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

tout ce que vous avez à faire est d'appeler le style.

Exemple d'implémentation

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

Une réponse légèrement plus difficile qui utilise ControlTemplate et a un effet d'animation (adapté de https://docs.microsoft.com/en-us/dotnet/framework/wpf/controls/customizing-the-appearance-of-an-existing- contrôle )

Dans votre dictionnaire de ressources, définissez un modèle de contrôle pour votre bouton comme celui-ci:

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

dans votre XAML, vous pouvez utiliser le modèle ci-dessus pour votre bouton comme ci-dessous:

Définissez votre bouton

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

J'espère que ça aide

Iakobos Karakizas
la source
0

Pour changer le style du bouton

1er: définir les styles de ressources

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

2e définir le code du bouton

                           <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ème code derrière

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