altso
altso

Reputation: 2370

Obtaining caret position in TextBox

How to get caret position (x, y) in the visible client zone in TextBox control? I need to add an auto complete feature to the text box.

I've found solution for WPF, but it can't be applied in Silverlight.

Upvotes: 4

Views: 1146

Answers (2)

rr-
rr-

Reputation: 14811

In addition to altso's answer, I'd like to mention that you actually need to call .Measure() and .Arrange() methods on the block for .ActualHeight and .ActualWidth to work, for example, like this (parameters may vary depending on your use case):

 block.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
 block.Arrange(new Rect(0, 0, block.DesiredSize.Width, block.DesiredSize.Height));
 double y = block.ActualHeight;

This is required in WPF, and advised in Silverlight (including SL5). Otherwise you'll end up having 0 in ActualHeight in WPF and weird numbers in Silverlight (in my case, these were coordinates of a bounding box around all text).


As a separate solution, you could use FormattedText class to do the same trick.

Upvotes: 2

altso
altso

Reputation: 2370

public class AutoCompleteTextBox : TextBox
{
    public Point GetPositionFromCharacterIndex(int index)
    {
        if (TextWrapping == TextWrapping.Wrap) throw new NotSupportedException();

        var text = Text.Substring(0, index);

        int lastNewLineIndex = text.LastIndexOf('\r');

        var leftText = lastNewLineIndex != -1 ? text.Substring(lastNewLineIndex + 1) : text;

        var block = new TextBlock
                        {
                            FontFamily = FontFamily,
                            FontSize = FontSize,
                            FontStretch = FontStretch,
                            FontStyle = FontStyle,
                            FontWeight = FontWeight
                        };

        block.Text = text;
        double y = block.ActualHeight;

        block.Text = leftText;
        double x = block.ActualWidth;

        var scrollViewer = GetTemplateChild("ContentElement") as ScrollViewer;

        var point = scrollViewer != null
                        ? new Point(x - scrollViewer.HorizontalOffset, y - scrollViewer.VerticalOffset)
                        : new Point(x, y);
        point.X += BorderThickness.Left + Padding.Left;
        point.Y += BorderThickness.Top + Padding.Top;

        return point;
    }
}

Upvotes: 5

Related Questions