WPF RichTextBox increment font size

2.3k views Asked by At

As the title suggests, my aim is to increment/decrement the font size of the current selection of text inside the RichTextBox.

This may seem trivial, and in fact it is - so long as the font size is the same for all text in the TextRange. When the selection contains text with different font sizes, the

range.GetPropertyValue(TextElement.FontSizeProperty);

which I use to get the previous value of the font size (necessary in order to know what to set the value to) returns DependencyProperty.UnsetValue .

Not only is this a problem, but also the fact that there isn't a method to increment the size, only one to explicitly set it to a given value is causing an issue here.

I've considered trying to parse the TextRange for sub ranges with different property values, but this seems like a really convoluted way to achieve something which should be trivial.

How do I go about this? Thanks in advance.

4

There are 4 answers

4
123 456 789 0 On

Get the TextRange through RichTextBox's Selection which will give you TextRange, and you have a double value for your fontsize. Try this

 public void SetFontSizeForSelection(TextRange selection, double newFontSize)
        {
            if ((newFontSize - 0) < double.Epsilon)
                newFontSize = 1;
            selection.ApplyPropertyValue(TextElement.FontSizeProperty, newFontSize);
        }
0
Mishax On

I think any implementation, if it existed, would ultimately have to do the exact same thing you propose so your options are limited:

If your concern is that this is a lot of operations, you could be right about that and the only conceptual shortcut I can think of would be to apply a ScaleTransform. This of course is only going to make it appear to work and it isn't going to change the properties of the selection.

If your concern is that this is a lot of clutter in your user code, you are also right but I'd suggest hiding that by making your own RichTextBox and implementing the IncrementSizeOfSelection and DecrementSizeOfSelection yourself.

1
Stephan On

I think the necessary operations are not too many. I've tried it with multiple different text sizes - this example only works when the selected text is enclosed in < RUN > elements. But it should be possible to extend the code for different elements like < span > Yet, I don't know how to handle something like < Paragraph >< Bold > Bolded < /Bold >< /Paragraph >

    private void sizeTextSel(int iVal)
    {
        TextSelection ts = _richTextBox.Selection;
        TextPointer tpStart = ts.Start;
        TextPointer tpEnd = ts.End;
        TextPointer tpRun = tpStart;

        int iSelLength = tpStart.GetOffsetToPosition(tpEnd);
        int iStartRunLength;
        object fontSizeSelection;
        int iTotalSelected = 0,iSelect;

        do
        {                   
            iStartRunLength = tpRun.GetTextRunLength(LogicalDirection.Forward);
            iSelect = iStartRunLength < iSelLength - iTotalSelected ? iStartRunLength : iSelLength - iTotalSelected;
            ts.Select(tpRun, tpRun.GetPositionAtOffset(iSelect,LogicalDirection.Forward));
            fontSizeSelection = ts.GetPropertyValue(TextElement.FontSizeProperty);
            if (fontSizeSelection != null)
                ts.ApplyPropertyValue(TextElement.FontSizeProperty, (double)fontSizeSelection + iVal);

            tpRun = tpRun.GetPositionAtOffset(iSelect + 1);
            while (tpRun != null && tpRun.Parent.GetType() != typeof(Run))
            {
                tpRun = tpRun.GetPositionAtOffset(1);
                //iOffset +=1;
            }
            iTotalSelected += iSelect+1;

        } while (tpRun != null && iTotalSelected < iSelLength);

        ts.Select(tpStart, tpEnd);
    }
0
Stephan On

I think this should work now... as I've commented in my last post, this takes care of the automatic merging of < run > elements when their textsize becomes same:

    private void sizeTextSel(int iVal)
    {
        TextSelection ts = _richTextBox.Selection;
        TextPointer tpStart = ts.Start;
        TextPointer tpEnd = ts.End;
        TextPointer tpRun = tpStart;

        int iSelLength = ts.Text.Length;
        int iStartRunLength;
        object fontSizeSelection;
        int iTotalSelected = 0, iSelect = 0,iNew=0;
        do
        {
            iStartRunLength = tpRun.GetTextRunLength(LogicalDirection.Forward);
            iSelect = iStartRunLength < iSelLength - iTotalSelected ? iStartRunLength : iSelLength - iTotalSelected;
            if (iStartRunLength > 0)
            {
                iSelect = iSelect == 0 ? 1 : iSelect;
                ts.Select(tpRun, tpRun.GetPositionAtOffset(iSelect, LogicalDirection.Forward));
                fontSizeSelection = ts.GetPropertyValue(TextElement.FontSizeProperty);
                if (fontSizeSelection != null)
                    ts.ApplyPropertyValue(TextElement.FontSizeProperty, (double)fontSizeSelection + iVal);
                iNew = tpRun.GetTextRunLength(LogicalDirection.Forward);
                if (iNew==0)
                    tpRun = tpRun.GetPositionAtOffset(iSelect + 1, LogicalDirection.Forward);
                else
                    tpRun = tpRun.GetPositionAtOffset(iSelect, LogicalDirection.Forward);
            }
            else
            {
                if (tpRun.Parent.GetType() == typeof(FlowDocument))
                    iSelect = 2;
                else
                    iSelect = 0;
                tpRun = tpRun.GetPositionAtOffset(1, LogicalDirection.Forward);
            }

            iTotalSelected += iSelect;

        } while (tpRun != null && iTotalSelected < iSelLength);

        ts.Select(tpStart, tpEnd);
    }