1

In the image below, I have 3 buttons (UserControls) on which I changed the default mouseOver effect. In the picture, I'm currently hovering the button 1.

enter image description here

Here is the code I used:

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

My user control buttons:

<Button HorizontalContentAlignment="Stretch" Style="{StaticResource ButtonMouseOver}" VerticalContentAlignment="Stretch" Background="{Binding ButtonColor}" BorderThickness="0">

But now, I can't change the color of my buttons anymore with the Background property. Any ideas why?

thatguy
  • 21,059
  • 6
  • 30
  • 40

1 Answers1

1

When you override a ControlTemplate you have to be careful to use TemplateBinding to bind to properties of the templated target control, otherwise they take their default value or the explicit value that you have assigned in the template, but they cannot be overriden directly or in a Style.

In your example, you have to bind the Background of the Border with a TemplateBinding so that it uses the value from the Background property of the templated Button. You should do that for all properties of Button to enable different styles.

<ControlTemplate TargetType="{x:Type Button}">
   <Border Background="{TemplateBinding Background}">
   <!-- ...other definitions -->
</ControlTemplate>

From the documentation of TemplateBinding:

Links the value of a property in a control template to be the value of another property on the templated control.

Here is a simplified version of your control template with a template binding for background, as well as a default value defined in its style, that can be overriden in another style or directly on the button.

<Style x:Key="ButtonMouseOver" TargetType="{x:Type Button}">
   <Setter Property="Background"
           Value="#777777"/>
   <Setter Property="Template">
      <Setter.Value>
         <ControlTemplate TargetType="{x:Type Button}">
            <Border x:Name="MyBorder"
                    Background="{TemplateBinding Background}">
               <ContentPresenter HorizontalAlignment="Center"
                                 VerticalAlignment="Center"/>
            </Border>
            <ControlTemplate.Triggers>
               <Trigger Property="IsMouseOver"
                        Value="True">
                  <Setter TargetName="MyBorder"
                          Property="Background"
                          Value="#404040"/>
               </Trigger>
            </ControlTemplate.Triggers>
         </ControlTemplate>
      </Setter.Value>
   </Setter>
</Style>
thatguy
  • 21,059
  • 6
  • 30
  • 40
  • Well... now I can see the color change but button click and mouseOver don't work anymore – Émile Pettersen-Coulombe Aug 24 '20 at 20:46
  • In fact, when I use `TemplateBinding`, the background of the border will be the same as the background of my button? – Émile Pettersen-Coulombe Aug 24 '20 at 20:50
  • @ÉmilePettersen-Coulombe The mouse-over does not work, because you define it in a `Style` fro border. Do *not* do that, use triggers of the `ControlTemplate` instead, then it works. Look at this [example](https://learn.microsoft.com/en-us/dotnet/api/system.windows.controls.controltemplate.triggers?view=netcore-3.1). The `Border` is the root control in your template, so setting its `Background` will set the background for the button. – thatguy Aug 24 '20 at 20:57
  • I looked at this solution: https://stackoverflow.com/questions/20073294/change-color-of-button-when-mouse-is-over I don't really understand why or how I should use triggers of the `ControlTemplate` but if I put a background property on the button directly, there is no mouseOver triggered. If I put a background property it in the button.style section in a setter tag, the mouseOver is working. – Émile Pettersen-Coulombe Aug 24 '20 at 21:34
  • @ÉmilePettersen-Coulombe In your linked post, look at the answer below the accepted answer, it uses template triggers. The reason why you should use control template triggers is that they take [precedence](https://learn.microsoft.com/en-us/dotnet/framework/wpf/advanced/dependency-property-value-precedence#dependency-property-setting-precedence-list) over styles. – thatguy Aug 24 '20 at 22:03
  • @ÉmilePettersen-Coulombe I have added an example for your control template that does what you want. It also has a default background that is overridable and uses template triggers. – thatguy Aug 24 '20 at 22:12