Search code examples
wpfbindingcontroltemplate

wpf control with content template change background on mouseover


I'm really new to this. The code below displays the button perfectly, but I cannot get the rectangle fill within the button to change on mouse over. I have tried several different methods but none work. I've had a go at controltemplate.triggers as well as style.triggers. What am I doing wrong?

    <Window.Resources>
        <LinearGradientBrush x:Key="buttonbkgrnd" StartPoint="0,0" EndPoint="1,1">
            <GradientStop Color="#FF7D7DF1" Offset="0.0" />
            <GradientStop Color="white" Offset="0.25" />
            <GradientStop Color="#FF7D7DF1" Offset="0.75" />
        </LinearGradientBrush>
        <LinearGradientBrush x:Key="buttonhoverbkgrnd" StartPoint="0,0" EndPoint="1,1">
            <GradientStop Color="#FF28D366" Offset="0.0" />
            <GradientStop Color="white" Offset="0.25" />
            <GradientStop Color="#FFC4C4F7" Offset="0.75" />
        </LinearGradientBrush>
        <Style x:Key="{x:Type Button}" TargetType="{x:Type Button}">
            <Setter Property="Foreground" Value="Black"/>
            <Setter Property="FontWeight" Value="Bold"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Button}">
                        <Grid>
                            <Rectangle x:Name="btnback" StrokeThickness="8" RadiusY="10" RadiusX="10" Fill="{StaticResource buttonbkgrnd}" >
                                <Rectangle.Stroke>
                                    <LinearGradientBrush>
                                        <GradientStop Offset="0" Color="Gray"/>
                                        <GradientStop Offset="0.25" Color="LightGray"/>
                                        <GradientStop Offset="0.75" Color="Gray"/>
                                    </LinearGradientBrush>
                                </Rectangle.Stroke>
                                <Rectangle.Style>
                                    <Style TargetType="{x:Type Rectangle}">
                                        <Style.Triggers>
                                            <DataTrigger Binding="{Binding Path=IsMouseOver,
                                     RelativeSource={RelativeSource FindAncestor,
                                     AncestorType={x:Type Button}}}" Value="true">
                                                <Setter Property="Fill" Value="{StaticResource buttonhoverbkgrnd}" />
                                            </DataTrigger>
                                        </Style.Triggers>
                                    </Style>
                                </Rectangle.Style>
                            </Rectangle>

                            <ContentPresenter
                                Margin = "10"
                                HorizontalAlignment="Center"
                                VerticalAlignment="Center"
                            />
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
...
window stuff ...
...
        <WrapPanel Margin="0,50,0,0" HorizontalAlignment="Center">
            <Button x:Name="BtnGo" Content="Go" HorizontalAlignment="Center" Margin="5,5,15,5" VerticalAlignment="Top" Width="172" Height="60" RenderTransformOrigin="1.881,0.729" FontSize="20" Click="BtnGo_Click" TabIndex="3" IsDefault="True" AutomationProperties.AcceleratorKey="g"/>
            <Button x:Name="BtnCancel" Content="Cancel" HorizontalAlignment="Center" Margin="15,5,5,5" VerticalAlignment="Top" Width="172" Height="60" RenderTransformOrigin="1.881,0.729" FontSize="20" TabIndex="4" AutomationProperties.AcceleratorKey="c" Click="BtnCancel_Click" />
        </WrapPanel>

Solution

  • <Rectangle ... Fill="{StaticResource buttonbkgrnd}">
    

    here Fill property has local value. Style.Trigger cannot override it.

    you can ...

    ... remove that local value and use Style Setter:

    <Rectangle.Style>
        <Style TargetType="{x:Type Rectangle}">
            <Setter Property="Fill" Value="{StaticResource buttonbkgrnd}" />
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=IsMouseOver,
                                               RelativeSource={RelativeSource FindAncestor,
                                               AncestorType={x:Type Button}}}" Value="true">
                    <Setter Property="Fill" Value="{StaticResource buttonhoverbkgrnd}" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Rectangle.Style>
    

    ... keep local value and use ContentTemplate.Trigger with TargetName:

    <ControlTemplate.Triggers>
        <Trigger Property="IsMouseOver" Value="true">
            <Setter TargetName="btnback" Property="Fill" Value="{StaticResource buttonhoverbkgrnd}" /> 
        </Trigger>
    </ControlTemplate.Triggers>
    

    in this case <Rectangle.Style> becomes redundant and can be removed