wpfwpf-controlsframeworkelement

Button foreground doesn't change when content is StackPanel


I have a button style defined where the template has a ContentPresenter with a name of "contentPresenter". It then has a trigger set up like this:

<ControlTemplate.Triggers>
    <Trigger Property="UIElement.IsEnabled" Value="False">
        <Setter Property="TextElement.Foreground" TargetName="contentPresenter" Value="#FF838383" />
    </Trigger>
</ControlTemplate.Triggers>

This trigger simply changes the foreground color of a button to gray when the button is disabled. However, I have one button in my application which does not have simple text as its content. The button looks like this:

<Button Grid.Column="3" Grid.Row="3" Grid.ColumnSpan="2"
            Margin="120 20 30 10"
            Command="{Binding SomeCommand}">
        <StackPanel Orientation="Horizontal">
            <Image Source="{Binding MyImage}" Margin="0 0 2 0"
                   Visibility="{Binding ShowMyImage, Converter={StaticResource BooleanToVisibilityConverter}}"/>
            <TextBlock Text="{Binding ButtonText}" />
        </StackPanel>
    </Button>

The foreground of this button is always the same whether the button is disabled or not. I'm thinking it's because the text for the button is in a textblock within the stackpanel in the content presenter, but I don't know how to get the foreground color changes to be applied to the inner textblock.

I tried changing the Property in the trigger to use "TextBlock.Foreground" instead of "TextElement.Foreground". I also tried binding the Foreground of the inner textblock to the foreground color of the closest ancestor of type FrameworkElement like this:

<TextBlock Text="{Binding ButtonText}" Foreground="{Binding RelativeSource={RelativeSource AncestorType={x:Type FrameworkElement}}, Path=(FrameworkElement.Foreground)}" />

None of this worked. What do I need to do to get the foreground color to apply to the TextBlock inside the StackPanel?


Solution

  • Your trigger should be in the Style, and should be setting Foreground on the Button itself, rather than on the ContentPresenter. Then it'll Just Work, with a custom template or with the default template. No need for any extra bindings.

    <Style TargetType="Button" x:Key="MyButtonStyle">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <Border Background="Beige" BorderBrush="Black" BorderThickness="1" Padding="6,2">
                        <ContentPresenter 
                            />
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Style.Triggers>
            <Trigger Property="IsEnabled" Value="False">
                <Setter Property="Foreground" Value="#FF838383" />
            </Trigger>
        </Style.Triggers>
    </Style>
    

    Usage:

    <Button
        IsEnabled="False"
        Style="{StaticResource MyButtonStyle}"
        >
        <StackPanel>
            <TextBlock 
            >Blah Blah</TextBlock>
            <Button>X</Button>
        </StackPanel>
    </Button>
    <Button Style="{StaticResource MyButtonStyle}" IsEnabled="False">Testing</Button>
    

    Screenshot (never mind my ugly template):

    enter image description here