Home > Software engineering >  How can I make an Placeholder/Watermark to my Richtextbox Element?
How can I make an Placeholder/Watermark to my Richtextbox Element?

Time:06-20

For an Placeholder/Watermark in an TextBox I use this Style get that to work:

<Style x:Key="placeHolder" TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TextBox}">
                <Grid Margin="15 0 15 0">
                    <TextBox Text="{Binding Path=Text,
                                        RelativeSource={RelativeSource TemplatedParent}, 
                                        Mode=TwoWay,
                                        UpdateSourceTrigger=PropertyChanged}"
                         x:Name="textSource" TextWrapping="Wrap"
                             BorderBrush="Red" AcceptsReturn="True"
                                       BorderThickness="0"
                         Background="Transparent"
                         Panel.ZIndex="2" />
                    <TextBox Text="{TemplateBinding Tag}" TextWrapping="Wrap"  Background="{TemplateBinding Background}" Panel.ZIndex="1">
                     <TextBox.Style>
                         <Style TargetType="{x:Type TextBox}">
                             <Setter Property="BorderThickness" Value="0"/>
                             <Setter Property="Foreground" Value="Transparent"/>
                             <Style.Triggers>
                                 <MultiDataTrigger>
                                     <MultiDataTrigger.Conditions>
                                         <Condition Binding="{Binding Path=Text, Source={x:Reference textSource}}" Value="" />
                                         <Condition Binding="{Binding printcontrol}" Value="True"/>
                                      </MultiDataTrigger.Conditions>
                                      <Setter Property="Foreground" Value="LightGray"/>
                                      <Setter Property="Visibility" Value="Hidden"/>
                                 </MultiDataTrigger>
                                 <DataTrigger Binding="{Binding Path=Text, Source={x:Reference textSource}}" Value="">
                                        <Setter Property="Foreground" Value="LightGray"/>
                                 </DataTrigger>
                                </Style.Triggers>
                            </Style>
                        </TextBox.Style>
                    </TextBox>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

But now I need to use an RichTextBox and now that doesn't work for that so what Ive tried is something like that:

<RichTextBox x:Name="Placeholder" Height="20" IsHitTestVisible="True" VerticalAlignment="Top" Margin="0,20,298.8,0" Foreground="DarkGray" HorizontalAlignment="Right" Width="214">
    <FlowDocument>
       <Paragraph>
            <Run Foreground="Black">
                <Run.Style>
                    <Style TargetType="{x:Type Run}">  
                               
                    
                    <Setter Property="Foreground" Value="Transparent"/>
                    <Style.Triggers>
                        <MultiDataTrigger>
                            <MultiDataTrigger.Conditions>
                                <Condition Binding="{Binding Path=Text, Source={x:Reference textSource}}" Value="" />
                                <Condition Binding="{Binding printcontrol}" Value="True"/>
                            </MultiDataTrigger.Conditions>
                            <Setter Property="Foreground" Value="LightGray"/>
                            <Setter Property="FontSize" Value="0.004"/>
                        </MultiDataTrigger>
                        <DataTrigger Binding="{Binding Path=Text, Source={x:Reference textSource}}" Value="">
                            <Setter Property="Foreground" Value="LightGray"/>
                        </DataTrigger>
                    </Style.Triggers> 
                    </Style>
                </Run.Style>
            </Run>                               
        </Paragraph>
    </FlowDocument>                        
</RichTextBox>

But that didn't work. Has someone an Idea how to get Placeholder RichTextBox?

End Result should be something like that:

Picture1

CodePudding user response:

Define a dependency property (boolean type) that will determine when show or hide a placeholder. The only problem here is how to determine the FlowDocument is empty or not? Because of the RichTextBox doesn’t have a method that return state of the document.

I think one of a good solution (regarding performance) described in the following post: Detect if a RichTextBox is empty.

The code below contains the OnDocumentChanged() method that uses solution from the mentioned post:

public partial class MainWindow : Window
{
    public bool IsDocumentEmpty
    {
        get { return (bool)GetValue(IsDocumentEmptyProperty); }
        set { SetValue(IsDocumentEmptyProperty, value); }
    }
    
    public static readonly DependencyProperty IsDocumentEmptyProperty =
        DependencyProperty.Register("IsDocumentEmpty", typeof(bool), typeof(MainWindow), new PropertyMetadata(false));

    public MainWindow()
    {
        InitializeComponent();            
    }

    private void OnDocumentChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
    {
        if (sender is RichTextBox rtb)
        {                
            int size = rtb.Document.ContentStart.GetOffsetToPosition(rtb.Document.ContentEnd);
            IsDocumentEmpty = (size == 0 // The document has not blocks. Example, after Ctrl A & Delete. 
                    || size == 2 // The document has 1 block without inlines. For example, 1 paragraph without inline(s).  
                    || size == 4); // The document has 1 block and 1 paragraph with empty inline. 
        }
    }
}

The XAML:

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        ...
        Height="350" Width="400">

    <Window.Resources>
        <ResourceDictionary>
            <Style TargetType="{x:Type TextBox}">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=IsDocumentEmpty}"
                                 Value="False">                        
                        <Setter Property="Visibility" Value="Hidden"/>
                    </DataTrigger>                  
                </Style.Triggers>
            </Style>
        </ResourceDictionary>
    </Window.Resources>

    <Grid>        
        <Grid>
            <RichTextBox x:Name="rtb" IsHitTestVisible="True" HorizontalAlignment="Right" 
                         TextChanged="OnDocumentChanged" 
                         Background="Transparent" Panel.ZIndex="2">
                <FlowDocument x:Name="fdoc"/>
            </RichTextBox>
            <TextBox Text=" Enter text..."  TextWrapping="Wrap" Panel.ZIndex="1" Foreground="DarkGray" />  
        </Grid>
    </Grid>
</Window>
  • Related