Search code examples
c#wpfxamltooltip

Tooltip for Textbox with maxlength property


I want to make a tooltip for my TextBoxes in XAML, and i want do do this with styling in Xaml.

The Tooltip should display something like Enter up to x characters, with x equal to the MaxLength property of the textbox. I only want to display the tooltip if the MaxLength is set.

What i have now is something like:

    <Style x:Key="ToolTipTextBox" TargetType="{x:Type TextBox}" BasedOn="{StaticResource StandardTextBox}">
        <Style.Triggers>
            <MultiDataTrigger>
                <MultiDataTrigger.Conditions>
                    <Condition Binding="{Binding MaxLength, RelativeSource={RelativeSource Self}, Converter={StaticResource valueLargerThanZero}}"  Value="True"></Condition>
                </MultiDataTrigger.Conditions>
                <Setter Property="ToolTip">
                    <Setter.Value>
                        <TextBlock Margin="0" Text="{Binding MaxLength, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type TextBox}}, StringFormat='Enter up to {0} characters'}"/>
                    </Setter.Value>
                </Setter>
            </MultiDataTrigger>
        </Style.Triggers>
    </Style>

The condition is working, so if there is a MaxLength set the tooltip is displayed. Only the binding inside the tooltip is not working.

Other stuff that i've tried is:

    <Style x:Key="ToolTipTextBox" TargetType="{x:Type TextBox}" BasedOn="{StaticResource StandardTextBox}">
        <Style.Triggers>
            <MultiDataTrigger>
                <MultiDataTrigger.Conditions>
                    <Condition Binding="{Binding MaxLength, RelativeSource={RelativeSource Self}, Converter={StaticResource valueLargerThanZero}}"  Value="True"></Condition>
                </MultiDataTrigger.Conditions>
                <Setter Property="ToolTip">
                    <Setter.Value>
                        <ToolTip Content="{Binding MaxLength, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type TextBox}}}" ContentStringFormat="{}Enter up to {0} characters"/>
                    </Setter.Value>
                </Setter>
            </MultiDataTrigger>
        </Style.Triggers>
    </Style>

This gives the same problem as the option shown above, but i cant style the tooltip properly.

Another thing i've tried is:

    <Style x:Key="ToolTipTextBox" TargetType="{x:Type TextBox}" BasedOn="{StaticResource StandardTextBox}">
        <Style.Triggers>
            <MultiDataTrigger>
                <MultiDataTrigger.Conditions>
                    <Condition Binding="{Binding MaxLength, RelativeSource={RelativeSource Self}, Converter={StaticResource valueLargerThanZero}}"  Value="True"></Condition>
                </MultiDataTrigger.Conditions>
                <Setter Property="ToolTip" Value="{Binding MaxLength, RelativeSource={RelativeSource Self}, StringFormat='Enter up to {0} characters'}"/>
            </MultiDataTrigger>
        </Style.Triggers>
    </Style>

But this way the string formatting won't work.

Something i've tried before and that has worked was:

    <Style x:Key="ToolTipTextBox" TargetType="{x:Type TextBox}" BasedOn="{StaticResource StandardTextBox}">
        <Setter Property="DataContext"  Value="{Binding RelativeSource={RelativeSource Self}}"/>
        <Style.Triggers>
            <MultiDataTrigger>
                <MultiDataTrigger.Conditions>
                    <Condition Binding="{Binding MaxLength, Converter={StaticResource valueLargerThanZero}}"  Value="True"></Condition>
                </MultiDataTrigger.Conditions>
                <Setter Property="ToolTip">
                    <Setter.Value>
                        <TextBlock Margin="0" Text="{Binding MaxLength ,StringFormat='Enter up to {0} characters'}"/>
                    </Setter.Value>
                </Setter>
            </MultiDataTrigger>
        </Style.Triggers>
    </Style>

But this way the DataContext for the TextBox, and my other bindings dont work anymore.

Does anyone have a solution that (favorably) only includes XAML?

EDIT

While using a converter for MaxLength to the text Enter up to MaxLength characters it worked.

I used:

    <Style x:Key="ToolTipTextBox" TargetType="{x:Type TextBox}" BasedOn="{StaticResource StandardTextBox}">
        <Style.Triggers>
            <DataTrigger Binding="{Binding MaxLength, RelativeSource={RelativeSource Self}, Converter={StaticResource valueLargerThanZero}}"  Value="True">
                <Setter Property="ToolTip" Value="{Binding MaxLength, RelativeSource={RelativeSource Self}, Converter={StaticResource textBoxToolTipConverter}}"/>
            </DataTrigger>
        </Style.Triggers>
    </Style>

Solution

  • MultiDataTrigger, as name implies, is meant to be used with many conditions. You actually never used more than one. You can leverage of couple options:

    1. Create style for textBox and within set default ToolTip to "Enter up to.." and in style trigger check whether MaxLength equals either null or 0, if so set ToolTip empty.
    2. Bind ToolTip property to MaxLength and in converter assign value based on whether MaxLength is set

    EDIT

     <TextBox Text="Text" MaxLength="55">
            <TextBox.Style>
                <Style TargetType="TextBox">
                    <Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=MaxLength,StringFormat='Enter up to {0} characters'}"/>
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=MaxLength}" Value="0">
                            <Setter Property="ToolTip" Value="{x:Null}"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </TextBox.Style>
        </TextBox>
    

    This will display maxLength since ToolTip needs to have StringFormat set in diffrent way. I refer you to this post. All in all you end up being forced to create converter.