wpfcontroltemplates

WPF Style Triggers TemplateBinding


I'm new to WPF and I am struggling to find the solution to what I'm trying to do as I'm still a little uncertain as to whether I'm doing this correctly.

I have the following style defined for a button

<Style x:Key="ToolBarButtonStyle" TargetType="{x:Type Button}">
    <Setter Property="Margin" Value="5" />
    <Setter Property="BorderBrush" Value="White" />
    <Setter Property="Background" Value="{DynamicResource CompanyBlue}" />
    <Setter Property="Foreground" Value="White" />
    <Setter Property="FontWeight" Value="Bold" />
    <Setter Property="FontSize" Value="20" />
    <Setter Property="Width" Value="100" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">               
                <Border x:Name="ButtonBorder" BorderThickness="5" CornerRadius="5"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        Background="{TemplateBinding Background}"
                        Width="{TemplateBinding Width}">
                    <ContentPresenter Margin="10" HorizontalAlignment="Center" VerticalAlignment="Center" />
                </Border>


            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Style.Triggers>
        <Trigger Property="IsMouseOver" Value="True">
            <Setter Property="Button.Background">
                <Setter.Value>
                    <LinearGradientBrush StartPoint="0,-0.2" EndPoint="0,1.2">
                        <LinearGradientBrush.GradientStops>
                            <GradientStop Color="White" Offset="0" />
                            <GradientStop Color="{ORIGINAL-COLOR}" Offset="0.5" />
                            <GradientStop Color="White" Offset="1" />
                        </LinearGradientBrush.GradientStops>
                    </LinearGradientBrush>
                </Setter.Value>
            </Setter>
        </Trigger>
    </Style.Triggers>
</Style>

In the XAML, where I have put the placeholder {ORIGINAL-COLOR}, I essentially want this to be the value that is used previously set with {TemplateBinding Background} for the control template of the style.

I've seen suggestions that I should use {Binding RelativeSource={RelativeSource TemplatedParent}, Path=Background} but this is not working.

Thanks in advance for any help.


Solution

  • I believe the problem is that LinearGradientBrush is not a FrameworkElement and doesn't belong to layout tree. Only FrameworkElements have DataContext property and in consequence can make use of bindings. What you're trying to do is to set up a Binding on GradientStop.

    Your trigger should look like this:

                <Trigger Property="IsMouseOver" Value="True">
                    <Setter Property="Button.Background" 
                            Value="{TemplateBinding Background, Converter={StaticResource myConverter}}">
                    </Setter>
                </Trigger>
    

    And myConverter is a custom converter class that will take value of Background and return a complete LinearGradientBrush instance created from input brush. I'll assume you know how to write converters. Remember it needs to be added to resources.

    More or less something like this:

        class BrushToGradient : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var brush = (Brush)value;
            var gradient = new LinearGradientBrush();
    
            //Make it manually
            gradient.GradientStops.Add(...);
            //...
            return gradient;
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }