Click here to Skip to main content
15,881,709 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi, I used the following algorithm to create a custom cursor for TextBox:
XAML
<Window.Resources>
    <Style x:Key="{x:Type TextBox}" TargetType="{x:Type TextBox}">
        <Setter Property="CaretBrush" Value="Transparent"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type TextBox}">
                    <Grid>
                        <Border Background="{TemplateBinding Background}"
            x:Name="TextBox" BorderBrush="DarkGray"
            BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="9">
                            <ScrollViewer x:Name="PART_ContentHost"/>
                        </Border>
                        <Canvas ClipToBounds="True">
                            <Border x:Name="TextBoxCaret" Width="1.5" Margin="{Binding ElementName=TextBox,Path=Value}" Padding="4,4,0,0" Visibility="Collapsed" Background="Transparent">
                                <Border.Triggers>
                                    <EventTrigger RoutedEvent="Border.Loaded">
                                        <BeginStoryboard>
                                            <Storyboard RepeatBehavior="Forever">
                                                <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="Background.Color" FillBehavior="HoldEnd">
                                                    <ColorAnimationUsingKeyFrames.KeyFrames>
                                                        <EasingColorKeyFrame KeyTime="0:0:1.0" Value="Black"/>
                                                        <EasingColorKeyFrame KeyTime="0:0:2.0" Value="Transparent" />
                                                    </ColorAnimationUsingKeyFrames.KeyFrames>
                                                </ColorAnimationUsingKeyFrames>
                                            </Storyboard>
                                        </BeginStoryboard>
                                    </EventTrigger>
                                </Border.Triggers>
                            </Border>
                        </Canvas>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsEnabled" Value="False">
                            <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" TargetName="TextBox"/>
                            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                        </Trigger>
                        <Trigger Property="Width" Value="Auto">
                            <Setter Property="MinWidth" Value="100"/>
                        </Trigger>
                        <Trigger Property="Height" Value="Auto">
                            <Setter Property="MinHeight" Value="20"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>
<Grid>
    <TextBox x:Name="BookName_TextBox" GotFocus="BookName_TextBox_GotFocus" LostFocus="BookName_TextBox_LostFocus" Padding="4,4,0,0" HorizontalAlignment="Left" Height="30" TextWrapping="Wrap" VerticalAlignment="Top" Width="267" Margin="21,64,0,0"/>
</Grid>

Code behind:
C#
public void MoveCaret(TextBox TextBoxName)
{
    TextBoxName.LayoutUpdated += (sender, e) =>
    {
        switch (TextBoxName.GetRectFromCharacterIndex(TextBoxName.CaretIndex).IsEmpty)
        {
            case true:
                return;
            default:
                //We use the caret index to determine the cursor position of the TextBox in this section, and then we use that position to set the Border position.
                var Rect = TextBoxName.GetRectFromCharacterIndex(TextBoxName.CaretIndex);
                Border Caret = TextBoxName.Template.FindName("TextBoxCaret", TextBoxName) as Border;
                Canvas.SetLeft(Caret, Rect.Left);
                Canvas.SetTop(Caret, Rect.Top);
                Caret.Height = Rect.Height;
                break;
        }
    };
}

private void BookName_TextBox_GotFocus(object sender, RoutedEventArgs e)
{
    MoveCaret(BookName_TextBox);
    var Border = BookName_TextBox.Template.FindName("TextBoxCaret", BookName_TextBox) as Border;
    Border.Visibility = Visibility.Visible;
}

private void BookName_TextBox_LostFocus(object sender, RoutedEventArgs e)
{
    var Border = BookName_TextBox.Template.FindName("TextBoxCaret", BookName_TextBox) as Border;
    Border.Visibility = Visibility.Collapsed;
}

The result:
Click to see
As you can see in the image below, if I use the algorithm mentioned above, the cursor is always at the end of the text; but, if I don't use that algorithm, the cursor will be at the proper location.
Custom (using the algorithm):
Click to see
Standard (without using the algorithm):
Click to see
How can the above algorithm's problem be solved?
If someone answers correctly, I will give them 5 stars.
Thanks.

What I have tried:

I tried using the FlowDirection property, but nothing happened.
Posted
Updated 2-Aug-22 3:51am
v7
Comments
Member 15627495 6-Jun-22 6:26am    
is the carret index the same thing of cursor position ?

the carret seems to be the position of the 'text field', ( because it's basically a field compounds by 'columns and lines'
carret is about offset in the text field, but cursor is the position to write in the text field.

you're acting on the wrong stack.

try with 'selectionstart' , and 'selectedText' members.
Reza jafery 6-Jun-22 10:59am    
Thank you for your feedback.
When I use the "SelectionStart" property, I didn't obtain any results.
CHill60 1-Aug-22 9:00am    
"If someone responds correctly, I'll give them a "Reputation point"." - If someone does respond correctly please do not give them one "star" - Reputation points are earned by answering questions, posting comments, etc etc etc. and by having a post "up voted". One star is actually a downvote and will result in reputation points being deducted from the member. If an answer is useful to you then you can "accept" the answer and the member will get more points.
See Member Reputation System[^]
Reza jafery 1-Aug-22 10:40am    
I mean 5 stars
CHill60 1-Aug-22 10:45am    
:thumbsup: :)

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900