none
WordPad like text color changing capabilities in a RichTextBox

    Question

  • I'm using a RichTextBox to create a simple WordPad like feature for my application.  My desired functionality is that users may enter text, and at anytime click on one of eight color buttons (which I have created just above the RichTextBox) to change the color of the entered text from the current caret position forward.  If text is selected (hilighted) and a color button is pressed, then the selected text should turn to that color.  In other words, the functionality I'm looking for is basically that of windows WordPad.

    So far, I am able to change the color of selected text by first reading in the RichTextBox's Selection's Start and End points, and then changing the ForegroundProperty of the selected area to the desired color brush.  For example, given a RichTextBox rtb and a SolidColorBrush currentBrush:

    Code Start:

    TextPointer tp1 = rtb.Selection.Start;
    TextPointer tp2 = rtb.Selection.End;
    TextRange tr = new TextRange(tp1, tp2);
    tr.ApplyPropertyValue(TextElement.ForegroundProperty, currentBrush);

    Code End:

    However, I am unable to figure out how to change the color of the text at the current caret position.  I have tried changing the RichTextBox's Foreground brush, but that not only changes the current text color but also every previous instance of the current text color to the new text color.  All I'm looking for when the text color is changed and there is no selection is for the text written from here on in to take in the new color, without any changes to the previous text.  Any ideas?
    Thursday, August 30, 2007 1:08 AM

Answers

  • yeah.. creating an empty run with the color set with the caret within it should work

    Friday, August 31, 2007 2:36 PM
    Moderator
  • you could insert a run with a space and then remove the space once a char is entered...

    Wednesday, September 05, 2007 2:11 PM
    Moderator

All replies

  • Not entirely sure but a hint might be to create a new Run, set its foreground property to currentBrush and insert it at the current CaretPosition. Just make sure that any subsequent text entered ends up in the newly created run (Might have to adjust CaretPosition here) and your formatting should be aplied properly.

    Just an idea...
    Thursday, August 30, 2007 9:00 AM
  • yeah.. creating an empty run with the color set with the caret within it should work

    Friday, August 31, 2007 2:36 PM
    Moderator
  • Maybe it would be helpful if someone explained how to move the carret position into the newly created Run Smile

    Anyone?

    Monday, September 03, 2007 12:21 AM
  • I decided to try and implement the above suggestion but I ran into an interesting "problem"... If you have an RTB with som text in it, and you position the caret somewhere within this text, then execute the following:

    Code Snippet

     Run r = new Run("", this._sampleRtb.CaretPosition);
     r.Foreground = Brushes.Red;


    A new empty Run with its Foreground set to red is indeed inserted into the FlowDocument of the RTB at the current caretPosition. However, the next time you press a key to enter more text, this text will not end up in the newly created Run. It follows that of course you have to move the caretPosition to make sure that the next entered keystroke ends up in the above inserted Run. Question is, how do you do this?

    On way is to do something like the following:

    _sampleRtb.CaretPosition = r.ContentStart;

    however, since there is no content (text) in the new Run this will not move the caretPosition to the correct position.

    How would one go about implementing this?

    (I guess what I am trying to ask is, how do you move the caret position into an empty Run?)

    All the best!
    Tuesday, September 04, 2007 7:16 AM
  • Yes, that's the same problem as I'm now having; when I add a new run, and change its forground color to the new desired color, the next text I type in is still displayed in the old color.

    However, once I hit the enter key once, the subsequently entered text is all displayed in the new (correct) color.  I guess this means the caret does not enter the new run until the enter key is pressed?

     

    Tuesday, September 04, 2007 7:30 AM
  • This is because if you exevute the above code on an empty line (rather in an empty paragraph) WPF will not insert a NEW Run but rather set the foreground property of the current Run to the new color. If  you inspect the XAML FlowDocument being generated you can see this in effect...
    Tuesday, September 04, 2007 7:39 AM
  • you could insert a run with a space and then remove the space once a char is entered...

    Wednesday, September 05, 2007 2:11 PM
    Moderator
  • Something along these lines?

    Code Snippet

     

    Run r = new Run(" ", this._sampleRtb.CaretPosition);
     r.Foreground = Brushes.Red;

     

     

     

    Then Selection.Select the newly created space, move .Focus() to the RTB and thus the next time the user presses a key the selected space would be replaced with the pressek key character?

     

    I did implement this as a temporary solution though it really isn't very stable right? What if the user decides to perform som other action before clicking the RTB herselft (to give it focus), thereby de-selecting the carefully Selection.Select part?

     

    ... tricky....

     

    Thursday, September 06, 2007 4:35 AM
  • i agree... adding a run with a blank selected space and then writing over it works, to a point, but as globbe mentioned if the focus is changed then problems arise.  this seems like a really clumsy way of doing something as simple as changing text color in a rich text box... is there really no better way to accomplish this?!?

     

    i also find myself handling the color change differently depending on whether the new text comes at the end of a line or in the middle of previous text.  at the end of a line setting the CaretPosition to the newly created run's ContentEnd (not ContentStart) and then setting the Foreground of the new run to the desired brush seems to work fine.  its just entering code in the middle of a line that's not working so well

    Friday, September 07, 2007 12:53 AM
  • How are you handling the In-The-Middle-Of-A-Line case right now? Could you share your solution?

    Thanks!

    Friday, September 07, 2007 2:25 AM
  • Sure thing.  Basically I create the new run with a space, set text pointers before and after the space, select that area, and change the run brush to my current brush.  Its not perfect but is somewhat functional.

     

    textRun = new Run(" ", (TextPointer)myRichTextBox.CaretPosition);

    TextPointer start = myRichTextBox.CaretPosition;
    TextPointer end = start;
    end = end.GetNextInsertionPosition(LogicalDirection.Backward);
    myRichTextBox.Selection.Select(start, end);
    textRun.Foreground = mySolidColorBrush;

     

    Please also note that this will only be used if there is text after the carot on the current line; its best not to use at the end of a line or on a new line.

     

    If anyone figures out a better way to do this please let me know.

    Friday, September 07, 2007 9:20 AM
  • You dont need to use Run etc. Just create the range object

    Dim range As New TextRange(myRTB.Selection.Start, myRTB.Selection.End)

     

    Check

    If myRTB.Selection.isEmpty Then

    myRTB.Selection.ApplyPropertyValue(TextElement.ForegroundProperty, colorPallete.getColor)

    else

    range.ApplyPropertyValue(TextElement.ForegroundProperty, colorPallete.getColor)

    End If

     

    I know the solution is kinda wierd, but it works for me.

     

    • Proposed as answer by jiusing.pan Wednesday, August 29, 2012 9:54 AM
    Thursday, September 20, 2007 3:26 AM
  • I may be missing something here, but if there is no selection and the caret is within an already existing word, your solution sets the foreground color of the word (the current run) to the selected color. This means that if you position the caret within a wordboundry, invokes the 'SetColor-SomethingOrOther' command the word surounding the caret position is also colored with the selected color...

     

    Is this consistent with your own experience?

    Thursday, September 20, 2007 3:38 AM
  •  

    I agree to your point. But MS Word behaves the same way as well. Atleast Word 2007 does, not sure of the earlier versions though.
    Thursday, September 20, 2007 1:17 PM
  • Subrajit - the code you gave works well, but as globbe mentioned changing the color when the caret is in the middle of a word does change the color of the whole word.  This is actually not consistent with Word, I just did a test on the newest version and when the text color is changed and the caret is in the middle of a word the already existing text color is not altered, only the test entered from that point forward.

    HOWEVER, the text box that you enter text into to post on these forums (the text box I'm entering into now) behaves the way Subrajit said, with an entire words text color being changed if the caret is in the middle of the word and the color is changed.  So it all depends on what you're looking for.

    What I am trying to accomplish is the Word-like color changing scheme where if the text color is changed with the caret in the middle of a word only the text entered from that point forward is change and not the color of the already existing word.  Does anyone have any ideas on how to accomplish this?

     

    Friday, September 21, 2007 1:21 AM
  • This worked for me:

                    SolidColorBrush brush = new SolidColorBrush(color);

                    TextRange tr = new TextRange(rtb.Selection.Start, rtb.Selection.End);
                    if (tr.IsEmpty)
                    {
                        //Nothing selected, start this color where the cursor is
                        rtb.Selection.ApplyPropertyValue(TextElement.ForegroundProperty, brush);
                    }
                    else tr.ApplyPropertyValue(TextElement.ForegroundProperty, brush);

                    rtb.SetFocus();
    Thursday, March 11, 2010 7:02 PM