Question

I'm still learning Blend, so please bear with me. I have a toggle button in a WPF project and I need to change the text color for different states such as mouseover and checked. However, when I'm editing the template and I select the contentPresenter, the only brush is OpacityMask and it is not affected by any brush color changes.

I can of course change the text color by editing the style, but this is not useful as it is within the states I'm interesting in editing.

Basically, I simply want the text of the button to change on mouseover, hover, etc, this seems a reasonable thing to do, but the OpacityMask Brush of the ContentPresenter cannot be edited.

Someone mentioned to change the ContentPresenter into a ContentControl. This does work, but I now cannot edit the text for an instance of the button. Do I have to link the ContentControl to something?

Many thanks for any help. I'm stuck right here for a few hours and I've been searching everywhere for the answer, to no avail

Was it helpful?

Solution

You can do what your looking for without having to use a ContentControl and by just using the VisualStateManager

I can of course change the text color by editing the style, but this is not useful as it is within the states I'm interesting in editing.

So say for example the state to apply a new Foreground color to the text of your Button is MouseOver,

  • Firstly Blend does not create a Brush resource for Button.MouseOver.Foreground when editing a Button template.

so let's create one. (Just add the following line along with the other brush resources)

<SolidColorBrush x:Key="Button.MouseOver.Foreground" Color="Tomato" />
  • Now we can apply a Storyboard to the TextElement.Foreground of the contentPresenter.

so your VSM will look like:

<VisualStateManager.VisualStateGroups>
    <VisualStateGroup x:Name="CommonStates">
        <VisualState x:Name="Normal"/>
        <VisualState x:Name="MouseOver">
      <Storyboard>
        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="contentPresenter"
                                        Storyboard.TargetProperty="(TextElement.Foreground)">
          <DiscreteObjectKeyFrame KeyTime="0">
            <DiscreteObjectKeyFrame.Value>
              <SolidColorBrush Color="{Binding Source={StaticResource Button.MouseOver.Foreground}, Path=Color}" />
            </DiscreteObjectKeyFrame.Value>
          </DiscreteObjectKeyFrame>
        </ObjectAnimationUsingKeyFrames>
      </Storyboard>
        </VisualState>
        <VisualState x:Name="Pressed"/>
        <VisualState x:Name="Disabled"/>
    </VisualStateGroup>
</VisualStateManager.VisualStateGroups>

and that's it.

Do note what we're doing here would be fine only when the Content of the Button is just text, but since that's what your usage is as mentioned in your question, you should be fine.

Sidenote:

You can do the exact same thing by just switching the ContentPresenter to a TextBlock in the ControlTemplate.

If you need the Foreground to be available for any Content of the Button, then yeh just switch the ContentPresenter to a ContentControl and you can still your VSM Storyboard's in a very similar way.

Update:

To switch the ContentPresenter to a ContentControl, in your ControlTemplate just switch the actual element with the new one.

<ControlTemplate TargetType="{x:Type Button}">
  ...
  <ContentPresenter x:Name="contentPresenter" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" RecognizesAccessKey="True"/>
  ...
</ControlTemplate>

to:

<ControlTemplate TargetType="{x:Type Button}">
  ...
  <ContentControl x:Name="contentPresenter" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Content="{TemplateBinding Content}"/>
  ...
</ControlTemplate>

you would have to update their properties accordingly like for eg ContentControl does not support RecognizesAccessKeys and it also needs Content="{TemplateBinding Content}" set on it to actually show the content. With a ContentPresenter the Content property is set implicitly.

OTHER TIPS

Foreground property is present in Style. So you can edit Style and there you can set Foreground. It could be something like this

<Style.Triggers>
    <Trigger Property="IsChecked" Value="False">
        <Setter Property="Foreground" Value="Blue"/>
    </Trigger>
</Style.Triggers>

Or if you want to change it in ControlTemplate then you can do it like this.

<Trigger Property="IsChecked" Value="True">
   <Setter Property="TextBlock.Foreground" TargetName="contentPresenterName" Value="White"/>
</Trigger>

So in expression blend you do it like this

  1. Locate your Style in the Resources panel, and then click the Edit resource button next to the resource. Or right-click and choose Edit.
  2. Add trigger in Triggers panel.
  3. Go to Properties panel and change Foreground property.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top