Search code examples
c#wpfxamlbuttoncontroltemplate

How to make button highlight when hovered over using a template


Recently started WPF and am very new to XAML. I'm trying to make a calculator that looks similar to the IOS one. However, after I changed the Button to Ellipse, the highlighting when hovered over or clicking on stopped working, if also the highlighting issue were to be fixed, how would I go about changing the colour of it?

<Button x:Name="ButtonEquals" Grid.Column="4" Grid.Row="6" Width="47" Height="47"
        Content="=" Foreground="White"
        BorderBrush="{x:Null}" Background="#FFFF9500">
    <Button.Template>
        <ControlTemplate TargetType="Button">
            <Grid>
                <Ellipse Fill="#FFFF9500"/>
                <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
            </Grid>
        </ControlTemplate>
    </Button.Template>
</Button>

Solution

  • You can add a Trigger to the ControlTemplate and target the Ellipse by name assigning an x:Name and referring to it via TargetName. This way, you can define other states as well.

    <ControlTemplate TargetType="Button">
       <Grid>
          <Ellipse x:Name="MyEllipse" Fill="#FFFF9500"/>
          <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
       </Grid>
       <ControlTemplate.Triggers>
          <Trigger Property="IsDefaulted" Value="True">
             <Setter TargetName="MyEllipse" Property="Fill" Value="OrangeRed"/>
          </Trigger>
          <Trigger Property="IsMouseOver" Value="True">
             <Setter TargetName="MyEllipse" Property="Fill" Value="Blue"/>
          </Trigger>
          <Trigger Property="IsPressed" Value="True">
             <Setter TargetName="MyEllipse" Property="Fill" Value="Red"/>
          </Trigger>
          <Trigger Property="IsEnabled" Value="False">
             <Setter TargetName="MyEllipse" Property="Fill" Value="Gray"/>
          </Trigger>
       </ControlTemplate.Triggers>
    </ControlTemplate>
    

    This targets only the Fill of the Ellipse, without changing other controls in the template. However, the values are hardcoded and not changable from outside.

    If you want the template to be customizable to a certain degree, then you can put it in a Style and bind properties on the templated control using TemplateBinding or a RelativeSource with TemplatedParent for two-way and special scenarios. Additionally, you can add a FocusVisualStyle that allows to specify a template for keyboard focusing.

    <Style TargetType="Button">
       <Setter Property="Background" Value="#FFFF9500"/>
       <Setter Property="Foreground" Value="White"/>
       <Setter Property="FocusVisualStyle">
          <Setter.Value>
             <Style>
                <Setter Property="Control.Template">
                   <Setter.Value>
                      <ControlTemplate>
                         <Ellipse StrokeDashArray="1 2" Stroke="DarkGreen" StrokeThickness="2"/>
                      </ControlTemplate>
                   </Setter.Value>
                </Setter>
             </Style>
          </Setter.Value>
       </Setter>
       <Setter Property="Template">
          <Setter.Value>
             <ControlTemplate TargetType="Button">
                <Grid>
                   <Ellipse x:Name="MyEllipse" Fill="{TemplateBinding Background}"/>
                   <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
                </Grid>
                <ControlTemplate.Triggers>
                   <Trigger Property="IsDefaulted" Value="True">
                      <Setter TargetName="MyEllipse" Property="Fill" Value="OrangeRed"/>
                   </Trigger>
                   <Trigger Property="IsMouseOver" Value="True">
                      <Setter TargetName="MyEllipse" Property="Fill" Value="Blue"/>
                   </Trigger>
                   <Trigger Property="IsPressed" Value="True">
                      <Setter TargetName="MyEllipse" Property="Fill" Value="Red"/>
                   </Trigger>
                   <Trigger Property="IsEnabled" Value="False">
                      <Setter TargetName="MyEllipse" Property="Fill" Value="Gray"/>
                   </Trigger>
                </ControlTemplate.Triggers>
             </ControlTemplate>
          </Setter.Value>
       </Setter>
    </Style>
    

    If you want to reuse the style on multiple buttons, add it to a resource dictionary in scope and assign an x:Key to refer to it via StaticResource or DynamicResource.