Reputation: 403
I'm getting data from a web API that returns text, and formatting information. The formatting data only includes the type of formatting (bold, italic, etc.) and the range of that formatting. The main problem with this is, that two ranges can "collide" (for example the first 3 characters of a word are bold and italic but the last 3 characters are only italic). Example response
{
"text" : "This is an example text",
"inlineStyles" : [
{
"offsetFromStart" : 5,
"length" : 10,
"type" : "bold"
}
{
"offsetFromStart" : 10,
"length" : 10,
"type" : "italic"
}
]
}
I already tried doing this with a simple TextBlock and failed. And I also tried this with a RichTextBox but when I added a Span I couldn't insert it into its original position. I also tought about formatting each character with its own span or run but that would be very ugly and in general just a bad solution. (My main concern is speed..)
var tb = new RichTextBox();
var para = new Paragraph();
para.Inlines.Add("This is an example text") // Text parsed from the response
var startingPointer1 = para.ContentStart.GetPositionAtOffset(5);
var sp1 = new Span(startingPointer1, startingPointer1.GetPositionAtOffset(10));
sp1.FontWeight = FontWeights.Bold;
var startingPointer2 = para.ContentStart.GetPositionAtOffset(10);
var sp2 = new Span(startingPointer2 , startingPointer2 .GetPositionAtOffset(10));
sp2.FontStyle= FontStyles.Italic;
para.Inlines.Add(sp1);
para.Inlines.Add(sp2);
tb.Document.Blocks.Add(para);
This code appends it to the end and when combining multiple inline elements like in my example it doesn't work at all (because of the first problem.)
Upvotes: 3
Views: 253
Reputation:
I don't think you can overlap Runs/Spans like this, you'll have to find all the breaking points in your text and format each text range separately. It's similar to HTML, where
<bold>some<italic> bold italic</bold> and other </italic> text.
is not valid. In your case, you'll have a bold from (5,10), bolditalic from (11, 15) etc.
It's probably useful to find some kind of Range
class with methods to combine ranges, split, find overlaps, etc. A while ago I started with this.
EDIT: I don't exactly have an idea how to implement all this (last time I did something similar was almost 10 years ago), but you can try something like this:
List<Range<int>>
. Initially it contains a single Range(0, length of text).(0, start of style), (start of style, end of style), (end of style, end of text)
. Remove old range from the list and add new ones.FontWeights, FontStyles
and other enums, defined in System.Windows
. Modify a list, so that it contains, for example, List<Tuple<int, Stylesheet>>
. To calculate overlaps just use the first param in the Tuple.TextRange
s, apply stylesOther idea that might work:
TextRange
and apply a style.If I remember correctly, inserting style definition in the text also counts as characters, so you might need to adjust offsets when you insert style tags in the final text. Also, I believe it is doable just using TextBlock
.
As I said, I don't know if this works like described, but this might give you and idea.
Upvotes: 1
Reputation: 403
My current solution is that I go through every character one by one and scan through the ranges detecting if the current character is in any of them and then assigning a span to the character. This is not ideal at all, but it gets the job done. I'll try to implement an actual algorithm for this later. Until then, if you have any information that could help, please comment.
If anyone needs sample code of my current implementation I'd happily share it with you. (Even though it's not really efficient at all)
Upvotes: 0