I'm creating a base style for my text inputs, these will have a placeholder. I'm trying to bind the Text.IsEmpty
property but it does not exist. So I've tried the following
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
CornerRadius="{TemplateBinding Border.CornerRadius}">
<Grid>
<TextBlock x:Name="Placeholder" Visibility="Visible" Text="{TemplateBinding Tag}"></TextBlock>
<ScrollViewer Background="Transparent" Margin="0" x:Name="PART_ContentHost"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding ElementName=PART_ContentHost,Path=IsFocused}" Value="False" />
<Condition Binding="{Binding ElementName=PART_ContentHost, Path=Text.IsEmpty}" Value="True" />
</MultiDataTrigger.Conditions>
<Setter TargetName="Placeholder" Property="Visibility" Value="Collapsed"/>
</MultiDataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
For simplicity, I'll only write the multi-trigger here for everything else I've tried.
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding RelativeSource={x:Static RelativeSource.Self},Path=IsFocused}" Value="False" />
<Condition Binding="{Binding RelativeSource={x:Static RelativeSource.Self},Path=Text.IsEmpty}" Value="True" />
</MultiDataTrigger.Conditions>
<Setter TargetName="Placeholder" Property="Visibility" Value="Collapsed"/>
</MultiDataTrigger>
Both of which do not work, I'm not very deep into using RelativeSource
so maybe I'm using the wrong source property? Can anyone suggest what I should bind to for my conditions.
There should be no text, whitespaces count as no text.
Or if the input is focused the placeholder disappears.
The first issue I see is that your logic is flipped. Your trigger says that if the control is not focused and the text is empty, hide the placeholder. (I don't think that's what you want)
The second issue I see is that you're using data triggers in a control template. In a control template you can just use normal triggers since you have direct access to all the elements.
In my example below I made the placeholder Collapsed
by default. If one of the triggers fires, then it will set it to Visible
. I added an extra trigger to handle null
.
I also am using IsKeyboardFocusWithin
which tends to be more reliable.
Here is a working example:
<TextBox
Width="200"
Height="24"
Tag="Enter something...">
<TextBox.Style>
<Style BasedOn="{StaticResource {x:Type TextBox}}" TargetType="{x:Type TextBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding Border.CornerRadius}">
<Grid>
<TextBlock x:Name="Placeholder"
Text="{TemplateBinding Tag}"
Visibility="Collapsed" />
<ScrollViewer x:Name="PART_ContentHost"
Margin="0"
Background="Transparent" />
</Grid>
</Border>
<ControlTemplate.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsKeyboardFocusWithin" Value="False" />
<Condition Property="Text" Value="{x:Static sys:String.Empty}" />
</MultiTrigger.Conditions>
<Setter TargetName="Placeholder" Property="Visibility" Value="Visible" />
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsKeyboardFocusWithin" Value="False" />
<Condition Property="Text" Value="{x:Null}" />
</MultiTrigger.Conditions>
<Setter TargetName="Placeholder" Property="Visibility" Value="Visible" />
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</TextBox.Style>
</TextBox>
I hope this helps.