0

How can I use XAML Triggers to hide a TextBlock when text is entered into the TextBox in my Style. This is the code I have got now, which doesn't work, no errors, is just probably wrong. How do I go about doing this?

<Style TargetType="TextBox">
        <Setter Property="Background" Value="#FF22252C" />
        <Setter Property="Foreground" Value="White" />
        <Setter Property="Width" Value="200" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="TextBox">
                    <Border CornerRadius="5" Background="#FF22252C" Margin="3" MinWidth="{TemplateBinding MinWidth}">
                        <Grid>
                            <StackPanel Margin="8">
                                <ScrollViewer x:Name="PART_ContentHost"/>
                            </StackPanel>
                            <StackPanel>
                                <TextBlock Name="PART_TempText" Text="{TemplateBinding Name}" Foreground="#FF454954" Padding="8" />
                            </StackPanel>
                        </Grid>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="Text" Value="{x:Null}">
                            <Setter TargetName="PART_TempText" Property="Foreground" Value="Red" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
Martyn Ball
  • 4,679
  • 8
  • 56
  • 126

1 Answers1

2

I think this would work, I assume you would like to implement a placeholder/watermark like functionality in your TextBox

<Style x:Key="CustomTextBoxStyle" TargetType="TextBox">
    <Setter Property="Background" Value="#FF22252C" />
    <Setter Property="Foreground" Value="White" />
    <Setter Property="Width" Value="200" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="TextBox">
                <Border CornerRadius="5" Background="#FF22252C" Margin="3" MinWidth="{TemplateBinding MinWidth}">
                    <Grid>
                        <StackPanel Margin="8">
                            <ScrollViewer x:Name="PART_ContentHost"/>
                        </StackPanel>
                        <StackPanel>
                            <TextBlock Name="PART_TempText" Text="{TemplateBinding Name}" Foreground="#FF454954"
                                       Visibility="Collapsed"
                                       Padding="8" />
                        </StackPanel>
                    </Grid>
                </Border>
                <ControlTemplate.Triggers>
                    <DataTrigger Binding="{Binding Text.Count, RelativeSource={RelativeSource Self}}" Value="0">
                        <Setter TargetName="PART_TempText" Property="Visibility" Value="Visible" />
                    </DataTrigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

The idea is that you hide the TextBlock initially and if the TextBox's Text.Count is 0 (meaning no value is entered), you show the TextBlock.

Update

I have a solution for the issue you mentioned about PasswordBox, maybe it's not the prettiest (it's not), but I'll share it anyway :)

The reason why it doesn't work, it's because

One possible solution is the following:

Add a new attached property to your project:

public class PasswordBoxAttachedProperties
{
    public static readonly DependencyProperty IsPasswordEnteredProperty = DependencyProperty.RegisterAttached(
        "IsPasswordEntered", typeof (bool), typeof (PasswordBoxAttachedProperties), new PropertyMetadata(default(bool)));

    public static void SetIsPasswordEntered(DependencyObject element, bool value)
    {
        element.SetValue(IsPasswordEnteredProperty, value);
    }

    public static bool GetIsPasswordEntered(DependencyObject element)
    {
        return (bool) element.GetValue(IsPasswordEnteredProperty);
    }
}

Change the trigger in the PasswordBox's Style to the following:

<DataTrigger Binding="{Binding (local:PasswordBoxAttachedProperties.IsPasswordEntered), RelativeSource={RelativeSource Self}}" Value="False">
    <Setter TargetName="PART_TempText" Property="Visibility" Value="Visible" />
</DataTrigger>

local is the namespace mapping you use in your application.

Add a reference to System.Windows.Interactivity and create the following TriggerAction:

public class NotifyPasswordChangeTrigger : TriggerAction<PasswordBox>
{
    protected override void Invoke(object parameter)
    {
        AssociatedObject.SetValue(PasswordBoxAttachedProperties.IsPasswordEnteredProperty, !string.IsNullOrEmpty(AssociatedObject.Password));
    }
}

Finally, add this trigger in your PasswordBox:

<PasswordBox Name="Password">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="PasswordChanged">
            <local:NotifyPasswordChangeTrigger />
        </i:EventTrigger>
    </i:Interaction.Triggers>
</PasswordBox>

PS.: I don't think you should use the Name property as the placeholder/watermark. Probably you should create a new attached property for that so you could use it like this (and replace the bindings from Name to the new attached property in your styles of course):

<PasswordBox local:TextBoxAttachedProperties.Placeholder="Please enter password...">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="PasswordChanged">
            <local:NotifyPasswordChangeTrigger />
        </i:EventTrigger>
    </i:Interaction.Triggers>
</PasswordBox>
Community
  • 1
  • 1
Szabolcs Dézsi
  • 8,743
  • 21
  • 29