Kommi

Anyone know how this can be done I saw an earlier post here:

http://forums.microsoft.com/MSDN/ShowPost.aspx PostID=365476&SiteID=1

that states that you can assign a value to rtb.SelectionStart, but you can no longer do that now. SO how can it be done with the current build of WPF



Re: Windows Presentation Foundation (WPF) set cursor position in RIchTextBox

Siri Vellanki - MSFT

You can do it by setting rtb.CaretPosition or by setting rtb.SelectionStart or rtb.Selection.Select()

What makes you think that rtb.SelectionStart no longer works






Re: Windows Presentation Foundation (WPF) set cursor position in RIchTextBox

Kommi

Siri Vellanki - MSFT wrote:

You can do it by setting rtb.CaretPosition or by setting rtb.SelectionStart or rtb.Selection.Select()

What makes you think that rtb.SelectionStart no longer works

Unless I am really missing something here, I do not see any property or method for RichTextBox class (System.Windows.Controls) called SelectionStart. There is a rtb.Selection.Start but it is read only. rtb.Selection.Select() requires 2 textPointers as parameters. but that means that I first need to increment the TextPointer some how, and then pass it to Select(). So still dont know how to move the cursor foward since I cant find a way to increment the TextPointer.





Re: Windows Presentation Foundation (WPF) set cursor position in RIchTextBox

Peter Sarrett - MSFT

The easiest way to set the caret's position is to set RichTextBox.CaretPosition = position. This is functionally equivalent to calling RichTextBox.Select(position, position).

No matter which approach you use, you'll still need to learn how to work with TextPointers. RichTextBox does not operate on indices like TextBox does. TextBox only contains text, so indices are sufficient there. A RichTextBox can contain other TextElements-- formatting, images, hyperlinks-- which makes index-based addressing inadequate. RichTextBox therefore uses TextPointers to navigate its content.

To advance the caret to the next caret position, you would do something like this:

TextPointer moveTo = myRichTextBox.CaretPosition.GetNextInsertionPosition(LogicalDirection.Forward);

if (moveTo != null)

{

myRichTextBox.CaretPosition = moveTo;

}

To go backward instead of forward, just using LogicalDirection.Backward instead.

You might wonder, "What is an insertion position, anyway " From the docs:

An insertion position is a position where new content may be added without breaking any semantic rules for the associated content. In practice, an insertion position is anywhere in content where a caret may be positioned.

There are many other ways to manipulate TextPointers. For more information, see the docs at http://msdn2.microsoft.com/en-us/library/system.windows.documents.textpointer_members.aspx

- Peter






Re: Windows Presentation Foundation (WPF) set cursor position in RIchTextBox

LesterLobo - MSFT

RichTextBox rtb = new RichTextBox();

TextPointer tp = rtb.CaretPosition;

tp = tp.GetNextInsertionPosition(LogicalDirection.Forward);

rtb.Selection.Select(rtb.CaretPosition, tp);

the aboe selects one char starting from the current caret position... if you want to select somewhere other that the caret position, you can pass that pointer in instead of the caretposition.

HTH





Re: Windows Presentation Foundation (WPF) set cursor position in RIchTextBox

Kommi

OK that is making me understand what is going on a bit better. My problem is that I cannot still get it to function the way I need to.

let say I have a line of text:

Code Snippet

<Paragraph><Run>max went to the store</Run><Run FontWeight="Bold" Background="#FFFFFF00">to buy some fruit</Run></Paragraph>

and the cursor is currently on the word "store". How do I then move it to after "...fruit</run>" so as to insert some text





Re: Windows Presentation Foundation (WPF) set cursor position in RIchTextBox

LesterLobo - MSFT

Code Snippet

TextPointer tp = RTB.CaretPosition.Paragraph.ContentEnd.GetNextInsertionPosition(LogicalDirection.Backward);





Re: Windows Presentation Foundation (WPF) set cursor position in RIchTextBox

Kommi

OK almost, but my example should have been more general. I know about ContentEnd. But what if the text is this:

Code Snippet
<run>max went to the store</RUN><RUN Background="#FFFFFF00" FontWeight="Bold">to buy some fruit</RUN><RUN>and some meat</RUN><RUN>and some eggs</RUN><RUN>and a car</RUN><RUN>and a newspaper</RUN></PARAGRAPH>

and I wanted to move the carrot from "fruit</Run>" to "<run>and some eggs" In general I am having trouble figuring out how I move the carrot around from one set of tags to the other.





Re: Windows Presentation Foundation (WPF) set cursor position in RIchTextBox

Siri Vellanki - MSFT

TextPointer has API to help navigate through the document.

Please refer to http://msdn2.microsoft.com/en-us/library/system.windows.documents.textpointer_members.aspx

Examples:

textPointer.GetInsertionPosition(logicalDirection)

textPointer.GetNextInsertionPosition(logicalDirection)

textPointer.GetPositionAtOffset(offset, logicalDirection)

textPointer.GetNextContextPosition(logicalDirection)

Also you can use other helpers to know where you are like...

TextPointer.GetPointerContext(logicalDirection)






Re: Windows Presentation Foundation (WPF) set cursor position in RIchTextBox

Kommi

Yes I am aware of all of those methods. Unfortunately, I guess my problem lies in the bahavior of the TextPointer itself. Take the following code for example

Code Snippet

DataBox.BeginChange();

TextPointer startPosition = DataBox.Selection.Start;

Run r = new Run("text to insert", startPosition);

DataBox.EndChange();

startPosition is the current location of the carrot in my RichTextBox. I have debugged this code and found the following:

first off if you look at the non public members of startPosition there is a private field called charOffset which holds the index location of the DataBox.Selection.Start.

OK so If I run my app and there is no other text in the RichTextBox and the carot is on the first position, then if this code is executed the startPointer has an intial char offset of 0, and then has one of 14, the length of the string I inserted. So the TextPointer moved foward by itself after the insertion. No probs there.

BUT, if I type in some text first, say "hello world ", and then exeucte that code, then something different happens. startPosition first has a char offset of 12, which is the right edge of the "hello world " string. But after the code in executed and the "text to insert" is inserted, the new char off set IS STILL 12!!! Why is that Why does the startPosition not move if there is already text in the RichTextBox Honestly, this is driving me nuts. I wish I could just use all the TextPointer methods to move it around, if only the damn pointer remained consistent in its behavior!

Ok I am going to include my example:

Window1.xaml

Code Snippet

<Window x:Class="TextPointerTest.Window1"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

Title="TextPointerTest" Height="300" Width="300"

>

<Grid>

<RichTextBox Margin="18,16,13,126" Name="rtb" />

<Button Height="23" Margin="18,0,0,94" Name="b1" xmlns:onVerticalAlignment="http://schemas.microsoft.com/winfx/2006/xaml/presentation" VerticalAlignment="Bottom" HorizontalAlignment="Left" Width="75">Insert text</< FONT>Button>

</< FONT>Grid>

</< FONT>Window>

Window1.xaml.cs

Code Snippet

using System;

using System.Collections.Generic;

using System.Text;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Shapes;

namespace TextPointerTest

{

/// <summary>

/// Interaction logic for Window1.xaml

/// </summary>

public partial class Window1 : System.Windows.Window

{

public Window1()

{

InitializeComponent();

RoutedCommand insertCommand = new RoutedCommand("insertCommand", typeof(Window1));

//this will overwrite the default crtl+r command for the richTextBox and replace with my cutom command

rtb.InputBindings.Add(new InputBinding(insertCommand,

new KeyGesture(Key.R, ModifierKeys.Control)));

//add an event handler to the command and then add it to the DataBox

CommandBinding binding = new CommandBinding(insertCommand);

binding.Executed += new ExecutedRoutedEventHandler(this.insertText);

rtb.CommandBindings.Add(binding);

}

public void insertText(object sender, RoutedEventArgs args)

{

//rtb.BeginChange(); //absolutely neccesary!!!

TextPointer startPosition = rtb.CaretPosition.GetPositionAtOffset(0, LogicalDirection.Forward);

Run r = new Run("text to insert", startPosition);

}

}

}

if you run this code, and then use the crtl+R command to insert text, notice where the carot is. First type something then hit crtl+r, then just start the app again and do the crtl+r first. You will see what I am confused about





Re: Windows Presentation Foundation (WPF) set cursor position in RIchTextBox

Peter Sarrett - MSFT

The culprit here is LogicalDirection.

Every TextPointer, including the CaretPosition, has a LogicalDirection of Forward or Backward. Think of it as gravity. When text is inserted at a TextPosition, imagine that position bouncing up into the air. Gravity-- LogicalDirection-- then pulls that position forward or backward as it falls, so that it winds up either at the front (Forward) or back (Backward) of the newly-inserted text. The reasons for this behavior are a bit beyond the scope of this response, because it involves bidirectional text (a left-to-right language like English mixed with a right-to-left language like Hebrew).

Fortunately, this is under your control. You can't set the LogicalDirection on a TextPointer, but you can create a new TextPointer at the same position and add your text to that:

Code Snippet

TextPointer forward = rtb.CaretPosition.GetPositionAtOffset(0, LogicalDirection.Forward);

Run r = new Run("text to insert", forward);

Note that you don't need to set the CaretPosition at all to do this (as long as the only behavior you care about is through your custom insertText method. If you want to affect the gravity of a normal Paste, you'd need to set the caret-- but if the user types or navigates the caret, the editor may override your setting).

- Peter






Re: Windows Presentation Foundation (WPF) set cursor position in RIchTextBox

Kommi

Hey Peter, thanks for the reply but I tried using your code and the problem still exists. PLEASE NOTE I have changed the code in my post above to use your method of getting the pointer.

I just made the observation that the concept of "foward" for the TextPointer changes if you use the arrow keys to move the cursor arround. So if I type some text in, then hit foward on the curosr and hit crtl+r to insert the text, the cursor will not move to the positon after the insertion. But if I hit back on the cursor and the hit crtl+r then the cursor goes to the position after the inserted text. Is this a bug

Edit:

OK upon further debugging I have noticed the following: TextPointer has a non public member called "Edge" that differs depedning on which direction the cursor was traveling in the RichTextBox

if the cursor was going left to right (ie typing a word or navigating using the arrow keys), then the TextPointer object looks like the following:

http://www.kommi.com/max/BeforeEnd.jpg

if the cursor was going right to left (in my case I was moving it using the arrow keys, but I can imagine that typing in hebrew or arabic would have done the same) then the TextPointer object looks like this

http://www.kommi.com/max/BeforeStart.jpg

Notice the area I highlighted. Notice how the logicDirection is still "Foward" for both of them, but it looks like which diretion is "foward" has changed. When googling the System.Windows.Documents.ElementEdge, the only page that comes up is this:

http://msdn2.microsoft.com/en-us/library/aa480168.aspx saying that it is deprecated.

There must be a way to tell the RichTextBox or the TextPointer which direction foward is. Anyone got any ideas or suggestions





Re: Windows Presentation Foundation (WPF) set cursor position in RIchTextBox

Peter Sarrett - MSFT

Try this code:

Code Snippet

rtb.BeginChange();

TextPointer forward = rtb.CaretPosition.GetPositionAtOffset(0, LogicalDirection.Forward);

forward.InsertTextInRun("text to insert");

rtb.CaretPosition = forward;

rtb.EndChange();






Re: Windows Presentation Foundation (WPF) set cursor position in RIchTextBox

Kommi

yeah I tried that before and it did not work. For anyone who would like to help, here is the demo project in a compressed rar file: http://www.kommi.com/TextPointerTest.rar

As stated earlier, once you run it you press crtl+r to insert a piece of text. But hitting the arrow keys left and right before pressing crtl+r will cause the caret to end up in different positions, either before or after the insert. I am trying to find a way to control this behavior, so that the caret always ends up after the inserted text, no matter what.





Re: Windows Presentation Foundation (WPF) set cursor position in RIchTextBox

Peter Sarrett - MSFT

The code I posted above works in your app when I try it. The key difference is the use of InsertTextInRun instead of creating a new run and adding it.