wpfmultidatatrigger

Data triggers trying to get Text.IsEmpty or Text.IsNullOrEmpty property


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.


Solution

  • 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.