Search code examples
c#wpfxamltemplatebinding

Button With Changing Image behavior based on IsMouseOver Trigger Doesn't work with TemplateBinding Conent as Image Source


I am a bit new to XAML WPF and I tried to make a button that change it's behavior based on IsMouseOver Trigger and it worked with a static data (for single element), when I tried to generalize it didn't work

and here is my code before generalization:

<Style x:Key="ActionButton" TargetType="Button">
        <Setter Property="BorderBrush" Value="{StaticResource BorderColor}"/>
        <Setter Property="BorderThickness" Value="2"/>
        <Setter Property="Background" Value="#FF220A5B"/>
        <Setter Property="Foreground" Value="#FFFFFF"/>
        <Setter Property="Height" Value="50"/>
        <Setter Property="Width" Value="50"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Button}">
                    <Border CornerRadius="100"
                            Background="{TemplateBinding Background}"
                            BorderThickness="{TemplateBinding BorderThickness}"
                            SnapsToDevicePixels="True">
                        <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center">
                            <ContentPresenter.Content>
                                <Image x:Name="imagePresenter" Source="/Resources/del-closed.png" Stretch="Uniform"/>
                            </ContentPresenter.Content>
                        </ContentPresenter>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter TargetName="imagePresenter" Property="Source" Value="/Resources/del-opened.png"/>
                        </Trigger>
                        <Trigger Property="IsMouseOver" Value="False">
                            <Setter TargetName="imagePresenter" Property="Source" Value="/Resources/del-closed.png"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

and it worked like this:

False> enter image description here

True> enter image description here

and this is my code after generalization:

<Style x:Key="ActionButton" TargetType="Button">
        <Setter Property="BorderBrush" Value="{StaticResource BorderColor}"/>
        <Setter Property="BorderThickness" Value="2"/>
        <Setter Property="Background" Value="#FF220A5B"/>
        <Setter Property="Foreground" Value="#FFFFFF"/>
        <Setter Property="Height" Value="50"/>
        <Setter Property="Width" Value="50"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Button}">
                    <Border CornerRadius="100"
                            Background="{TemplateBinding Background}"
                            BorderThickness="{TemplateBinding BorderThickness}"
                            SnapsToDevicePixels="True">
                        <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center">
                            <ContentPresenter.Content>
                                <Image x:Name="imagePresenter" Source="{TemplateBinding Content}" Stretch="Uniform"/>
                            </ContentPresenter.Content>
                        </ContentPresenter>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter TargetName="imagePresenter" Property="Source" Value="{TemplateBinding Content}"/>
                        </Trigger>
                        <Trigger Property="IsMouseOver" Value="False">
                            <Setter TargetName="imagePresenter" Property="Source" Value="{TemplateBinding Tag}"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

I tried to make my own UserControl but I couldn't because I don't know how to put custom Properties that I can reference from the designer!

As you can see I was trying to bind it to Content and Tag Properties so I can write clean code on my main XAML file Is there anything I can do?

NOTE: I know that I can put a ContentPresenter in the called button but I really want my Button syntax to be like this

<Button x:Name="btnDelete" Content="/Resources/del-opened.png" Tag="/Resources/del-closed.png" Grid.Column="4" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="20" Style="{StaticResource ActionButton}"/>

Solution

  • {TemplateBinding } cannot be used in Triggers, it should be replaced with a regular Binding which uses RelativeSource={RelativeSource TemplatedParent}

    <ControlTemplate.Triggers>
        <Trigger Property="IsMouseOver" Value="True">
            <Setter TargetName="imagePresenter" Property="Source" 
                    Value="{Binding Content, RelativeSource={RelativeSource TemplatedParent}}"/>
        </Trigger>
        <Trigger Property="IsMouseOver" Value="False">
            <Setter TargetName="imagePresenter" Property="Source" 
                    Value="{Binding Tag, RelativeSource={RelativeSource TemplatedParent}}"/>
        </Trigger>
    </ControlTemplate.Triggers>