Is there a way to change Foreground of a TextBox ScrollViewer in xaml whithout change the local property?

309 views Asked by At

Is there a way to change the Foreground of a custom TextBox in xaml with triggers or visualstates without change the local main Foreground property?

Here is the xaml style of a generic custom TextBox with randomly chosen colors:

<Style TargetType="{x:Type local:CustomTextBox}">
    <Setter Property="Background" Value="White"/>
    <Setter Property="BorderBrush" Value="Black"/>
    <Setter Property="Foreground" Value="Black"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:CustomTextBox}">
                <Border x:Name="PART_Border"
                        Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="1">
                    <ScrollViewer x:Name="PART_ContentHost"
                                    HorizontalScrollBarVisibility="Hidden"
                                    VerticalScrollBarVisibility="Hidden"
                                    Focusable="False"/>
                </Border>
                <ControlTemplate.Triggers>
                    <!-- Can be IsMouseOver, IsFocused, etc... -->
                    <Trigger Property="IsMouseOver" Value="True"> 
                        <Setter TargetName="PART_Border" 
                                Property="Background" Value="Green"/>
                        <Setter TargetName="PART_Border" 
                                Property="BorderBrush" Value="DarkGreen"/>
                        <!-- The only method I know that works is this one
                             that changes the local property -->
                        <Setter Property="Foreground" Value="Yellow"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

I've tried to use these lines in trigger but everyone fails (does nothing):

<Setter TargetName="PART_ContentHost" Property="Foreground" Value="Yellow"/>
<Setter TargetName="PART_ContentHost" Property="TextBlock.Foreground" Value="Yellow"/>
<Setter TargetName="PART_ContentHost" Property="TextElement.Foreground" Value="Yellow"/>
<Setter TargetName="PART_Border" Property="TextBlock.Foreground" Value="Yellow"/>
<Setter TargetName="PART_Border" Property="TextElement.Foreground" Value="Yellow"/>

In Buttons the Foreground color can be changed by changing TextBlock.Foreground of the parent element (e.g. TextBlock.Foreground of PART_Border), but this not works with TextBoxes.

Changing the local property as this line does...

<Setter Property="Foreground" Value="Yellow"/>

...has the problem that if I change later the main Foreground property (from Black to Gray for example), the trigger cannot change it anymore to Yellow, for example with this:

<local:CustomTextBox ... Foreground="Gray"/>

VisualStates cannot interact even with the main Foreground property.

So is there another way I don't know to accomplish this in xaml or is it a limitation of wpf?

3

There are 3 answers

0
mm8 On

You could animate the property using a Storyboard. This will take effect over local values:

<Window ...>
    <Window.Resources>
        <Style TargetType="{x:Type local:CustomTextBox}">
            <Setter Property="Background" Value="White"/>
            <Setter Property="BorderBrush" Value="Black"/>
            <Setter Property="Foreground" Value="Black"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type local:CustomTextBox}">
                        <Border x:Name="PART_Border"
                            Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="1">
                            <ScrollViewer x:Name="PART_ContentHost"
                                        HorizontalScrollBarVisibility="Hidden"
                                        VerticalScrollBarVisibility="Hidden"
                                        Focusable="False"/>
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter TargetName="PART_Border" Property="Background" Value="Green"/>
                                <Setter TargetName="PART_Border" Property="BorderBrush" Value="DarkGreen"/>
                                <Trigger.EnterActions>
                                    <BeginStoryboard x:Name="sb">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetProperty="Foreground">
                                                <DiscreteObjectKeyFrame KeyTime="00:00:00" Value="{x:Static Brushes.Yellow}"/>
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </BeginStoryboard>
                                </Trigger.EnterActions>
                                <Trigger.ExitActions>
                                    <RemoveStoryboard BeginStoryboardName="sb" />
                                </Trigger.ExitActions>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
    <StackPanel>
        <local:CustomTextBox Margin="10" Text="sample text" Foreground="Red" />
    </StackPanel>
</Window>
0
MIHOW On

I know I'm late to the party, but since question has not been answered and recently I've struggled with the same problem with PART_ContentHost in the TextBox, here's my answear.

For me also non of the Setters mentioned in the question worked

<Setter TargetName="PART_ContentHost" Property="Foreground" Value="Yellow"/>
<Setter TargetName="PART_ContentHost" Property="TextBlock.Foreground" Value="Yellow"/>
<Setter TargetName="PART_ContentHost" Property="TextElement.Foreground" Value="Yellow"/>

The only way to set the Foreground in the ControlTemplate for the custom TextBox was to simply create identical ScrollViewer to the PART_ContentHost, for it's content put a TextBlock with desired Foreground, and toggle Visibility for this new ScrollViewer and PART_ContentHost based on IsEnabled property.

0
Klamsi On

What if you completely override the ControlTemplate?

    <TextBox Text="Hiho" Foreground="Red">
        <TextBox.Style>
            <Style TargetType="{x:Type TextBox}">
                <Setter Property="Background" Value="White"/>
                <Setter Property="BorderBrush" Value="Black"/>
                <Setter Property="Foreground" Value="Black"/>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type TextBox}">
                            <TextBox Name="TheContent" Text="{TemplateBinding Text}"/>

                            <ControlTemplate.Triggers>
                                <Trigger Property="IsMouseOver" Value="True">
                                    <Setter TargetName="TheContent" Property="Foreground" Value="Yellow"/>
                                </Trigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </TextBox.Style>
    </TextBox>