views:

27

answers:

2

Specifically, what I'd like is to have a user right-click in a TextBox, figure out and save the index position within the text where the right-click occurred, and then later insert some text at that position once the user makes a choice from the context menu that pops up because of the right click.

The tricky part is getting the index position based on the coordinates of the right-click.

This is in Silverlight 4.

        private int _insertPoint;
    private void userNotification_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
    {
        // Move and open the context menu relative to its container.
        contextMenu.HorizontalOffset = e.GetPosition(container).X;
        contextMenu.VerticalOffset = e.GetPosition(container).Y;
        contextMenu.IsOpen = true;

        // Get the click coordinates relative to the TextBox.
        int clickX = e.GetPosition(textBox).X;
        int clickY = e.GetPosition(textBox).Y;
        _insertPoint = ?; // Here's the problem.
    }

    private void SelectFieldToInsert(object sender, MouseButtonEventArgs e)
    {
        // Close the context menu.
        contextMenu.IsOpen = false;

        var item = sender as ListBoxItem;
        textBox.Text = textBox.Text.Insert(_insertPoint, "<" + item.Content + ">");
    }
+1  A: 

The TextBox.SelectionStart property on a textbox should help you. From the link:

If there is no selection, the SelectionStart value gets or sets the location of the cursor.

Ragepotato
I tried making use of SelectionStart, but the selection point doesn't move with a right-click.Thanks.
Whyte Russian
A: 

How about:

    // Get the click coordinates relative to the TextBox.
    int clickX = (int)e.GetPosition(textBox).X;
    int clickY = (int)e.GetPosition(textBox).Y;
    int startPosition = 0;
    double currentHeight = 0;
    double calculatedHeight = 0;
    int charIndex;

    TextBlock tb = new TextBlock();
    tb.Width = this.textBox.Width;
    tb.FontFamily = this.textBox.FontFamily;
    tb.FontSize = this.textBox.FontSize;
    for (charIndex = 0; charIndex < this.textBox.Text.Length; charIndex++)
    {
        tb.Text = this.textBox.Text.Substring(startPosition, charIndex - startPosition + 1);
        if (tb.ActualHeight > currentHeight)
        {
            if (currentHeight == 0)
            {
                currentHeight = tb.ActualHeight;
                calculatedHeight = currentHeight;
            }
            else
            {
                startPosition = charIndex + 1;
                charIndex++;
                tb.Text = this.textBox.Text.Substring(startPosition, charIndex - startPosition + 1);
                currentHeight = tb.ActualHeight;
                calculatedHeight += currentHeight;
            }
        }

        if (tb.ActualWidth > clickX && calculatedHeight > clickY) break;
    }

    _insertPoint = charIndex;

I won't lie and say it's elegant, but it appears to work reasonably well.

Andy Hopper
Thanks Andy. I did come across this approach in my Google research, but I neglected to mention that this is a multiline TextBox. It might be possible to adapt this approach to two dimensions, but the math seems complicated.
Whyte Russian
Ah, OK. I've updated the code to reflect that.
Andy Hopper
It's close (if I add the line "tb.TextWrapping = TextWrapping.Wrap") but it's not accurate enough to find the correct insertion point.Thanks for the attempt. This is for a prototype so I don't need to solve it right now. I may come back to the problem when we implement it for real.
Whyte Russian