Jak zmienić tło dla przycisku MouseOver w WPF?

93

Na mojej stronie mam przycisk z tym kodem 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>

Ale kiedy umieszczam kursor myszy nad przyciskiem, tło przycisku zmienia się na domyślne szare tło systemu Windows.
Jaki jest problem?

To jest zdjęcie przycisku przed i po najechaniu myszą:
Przed:
Przed
Po:
Po

Sepehr Mohammadi
źródło
Ale musisz uruchomić obraz Forward-48.pngi wyzwolić IsMouseOver, aby zmienić go na to samo Forward-48.png. Próbuję użyć twojego kodu z różnymi obrazami i wszystko działało dobrze.
Anatoliy Nikolaev
1
@anatoliy: To nie działa.
Sepehr Mohammadi
Po czym jest twój domyślny kolor? Gdzie indziej nie zmieniasz / nie ustawiasz tła przycisku? Twój kod działa dobrze.
Anatoliy Nikolaev

Odpowiedzi:

175

Aby usunąć domyślne MouseOverzachowanie Button, musisz zmodyfikować plik ControlTemplate. Zmiana Styledefinicji na następującą powinna załatwić sprawę:

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

EDYCJA: Jest kilka lat późno, ale tak naprawdę możesz ustawić pędzel do obramowania wewnątrz granicy, która tam jest. Idk, jeśli zostało to wskazane, ale nie wygląda na to, że było ...

Richard E.
źródło
1
To działa, ale przycisk Krawędzie znikną! Musiałem umieścić element <BorderBrush = "DarkGray" BorderThickness = "1"> wokół przycisku.
Venugopal M
4
@CF powodem tego jest to, że standardowy styl przycisku ma wewnątrz wyzwalacze ControlTemplate, więc zastępują one Stylewyzwalacze OP .
torvin
1
@torvin Wydaje się, że to coś wstecznego! Dlaczego domyślne wyzwalacze zdefiniowane przez użytkownika powinny zostać zastąpione? Rozumiem hierarchię, ControlTemplate jest powyżej stylu, ale nie rozumiem, dlaczego zastąpienie podstawowych ustawień takich jak te musi być tak trudne.
Fuselight
@Fuselight, wyzwalacz wewnątrz ControlTemplatezasadniczo mówi „Maluj obramowanie zgodnie z Backgroundkolorem. A jeśli mysz znajduje się nad przyciskiem - zamiast tego pomaluj obramowanie na ten kolor, podczas gdy w stylu masz dostęp tylko do Backgroundkoloru, a nie do podstawowego koloru obramowania. Widzę jednak, że
zwracasz
Ma to dodatkową zaletę w postaci usuwania niebieskiego pola, które pojawia się po najechaniu myszą, gdy używasz obrazu z przezroczystym tłem. W moim przypadku nie chciałem granicy, więc ustaw BorderThickness na 0.
Chuck Savage
22

Wszystkie dotychczasowe odpowiedzi obejmują całkowite zastąpienie domyślnego zachowania przycisków czymś innym. Jednak IMHO jest przydatne i ważne, aby zrozumieć, że można zmienić tylko część, na której Ci zależy , edytując istniejący, domyślny szablon dla elementu XAML.

W przypadku do czynienia z efektem najechania na przycisk WPF, zmiana wyglądu w WPF Buttonelementu spowodowany jest Triggerw domyślnym stylu dla Button, który opiera się na IsMouseOverwłasności i ustawia Backgroundi BorderBrushwłaściwości najwyższego poziomu Borderelementu w szablonie kontrolnym. Tego Buttonelementu tła jest pod Borderelementu tła, więc zmieniając Button.Backgroundwłaściwość nie przeszkadza efekt najechania z widzianym.

Przy pewnym wysiłku można by zastąpić to zachowanie własnym ustawiaczem, ale ponieważ element, na który trzeba wpłynąć, znajduje się w szablonie i nie jest bezpośrednio dostępny we własnym XAML, takie podejście byłoby trudne i zbyt skomplikowane IMHO.

Inną opcją byłoby użycie grafiki jako elementu Contentfor Buttonzamiast Background. Jeśli potrzebujesz dodatkowej zawartości zamiast grafiki, możesz połączyć je z obiektem Gridnajwyższego poziomu w treści.

Jeśli jednak chcesz po prostu całkowicie wyłączyć efekt najechania kursorem (zamiast go ukrywać), możesz użyć projektanta Visual Studio XAML:

  1. Edytując XAML, wybierz kartę „Projekt” .
  2. Na karcie „Projekt” znajdź przycisk, dla którego chcesz wyłączyć efekt.
  3. Kliknij ten przycisk prawym przyciskiem myszy i wybierz „Edytuj szablon / Edytuj kopię ...” . Wybierz w wyświetlonym monicie miejsce, w którym chcesz umieścić nowy zasób szablonu. Wydaje się, że to nic nie da, ale w rzeczywistości Projektant doda nowe zasoby tam, gdzie to powiedziałeś, i zmieni element przycisku, aby odwoływał się do stylu, który używa tych zasobów jako szablonu przycisku.
  4. Teraz możesz przejść do edycji tego stylu. Najłatwiej jest usunąć lub skomentować (np. Ctrl+ E, C) <Trigger Property="IsMouseOver" Value="true">...</Trigger>Element. Oczywiście w tym momencie możesz wprowadzić dowolną zmianę w szablonie.

Kiedy skończysz, styl przycisku będzie wyglądał mniej więcej tak:

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

(Uwaga: możesz pominąć p:kwalifikacje przestrzeni nazw XML w rzeczywistym kodzie… Podaję je tutaj tylko dlatego, że program formatujący kod XML przepełnienia stosu jest zdezorientowany przez <Style/>elementy, które nie mają w pełni kwalifikowanej nazwy z przestrzenią nazw XML.)

Jeśli chcesz zastosować ten sam styl do innych przycisków, możesz po prostu kliknąć je prawym przyciskiem myszy i wybrać „Edytuj szablon / Zastosuj zasób” i wybrać styl, który właśnie dodałeś do pierwszego przycisku. Możesz nawet ustawić ten styl jako domyślny styl dla wszystkich przycisków, używając zwykłych technik stosowania stylu domyślnego do elementów w języku XAML.

Peter Duniho
źródło
6
Dzięki wielkie. To jedyna tolerowana odpowiedź tutaj
Jared Beach
13

To działało dobrze dla mnie.

Styl przycisku

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

Przycisk

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

Uwagi

  • Na przycisku wyświetlany jest mały niebieski krzyżyk, podobny do tego używanego do zamykania okna.
  • Ustawiając tło siatki na „Przezroczyste”, dodaje najgrubsze, co oznacza, że ​​jeśli mysz znajdzie się w dowolnym miejscu nad przyciskiem, to zadziała. Pomiń ten znacznik, a przycisk zaświeci się tylko wtedy, gdy wskaźnik myszy znajdzie się nad jedną z linii wektora w ikonie (nie jest to zbyt użyteczne).
Contango
źródło
1
To świetna odpowiedź, ale co ze zmianą Strokekoloru również po najechaniu kursorem Border, bez najeżdżania tylko na Path?
Nateous
1
Ta x:Key="TransparentStyle"część i użycie były dla mnie ważne, aby się tam dostać ... Dzięki!
nrod
6

Po prostu chcę udostępnić mój styl przycisku z mojego ResourceDictionary, którego używałem. Możesz dowolnie zmieniać tło onHover w wyzwalaczach stylu. „ ColorAnimation To = * żądany BG (tj. # FFCEF7A0)”. Przycisk BG również automatycznie powróci do swojego pierwotnego BG po przejściu w stan mouseOver. Możesz nawet ustawić szybkość przejścia.

Słownik zasobów

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

wszystko, co musisz zrobić, to nazwać styl.

Przykładowe wdrożenie

<Button Style="{StaticResource Flat_Button}" Height="Auto"Width="Auto">  
     <StackPanel>
     <TextBlock Text="SAVE" FontFamily="Arial" FontSize="10.667"/>
     </StackPanel>
</Button>
Justin Adrias
źródło
3

Nieco trudniejsza odpowiedź, która używa ControlTemplate i ma efekt animacji (zaadaptowana z https://docs.microsoft.com/en-us/dotnet/framework/wpf/controls/customizing-the-appearance-of-an-existing- kontrola )

W słowniku zasobów zdefiniuj szablon kontrolny dla swojego przycisku, taki jak ten:

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

w swoim XAML możesz użyć powyższego szablonu dla swojego przycisku, jak poniżej:

Zdefiniuj swój przycisk

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

Mam nadzieję, że to pomoże

Iakobos Karakizas
źródło
0

Aby zmienić styl przycisków

1: zdefiniuj style zasobów

<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. zdefiniowanie kodu przycisku

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

Trzeci kod za

    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
źródło