Highlight line(s)/characters in WPF - wpf

Scenario
I am currently developing an application. Within this application, I have a TextBox/RichTextBox. I have not decided on the control yet. Within this control, there will be a few paragraphs of text.
Problem
I want to be able to highlight a range of lines, or particular characters within that line, using two given numbers. What would the easiest way to do this be?

Use RichTextBox. You can't use TextBox, that is because TextBox has only one style applied to all text.
Use the TextRange.ApplyPropertyValue method. A TextRange is specified by its starting and ending position, which are two TextPointer.
Something like this
var startingPos = RichTextBox1.ContentStart.GetPositionAtOffset(n1, LogicalDirection.Forward);
var endingPos = startingPos.GetPositionAtOffset(n2 - n1, LogicalDirection.Forward);
var textrange = new TextRange(startingPos, endingPos);
textrange.ApplyPropertyValue(TextElement.BackgroundProperty, Brushes.DarkRed);
You have to carefully calculate the offsets of the starting and ending positions, taking linebreaks into account.

Related

How to find the TextRange of the Nth word in a WPF RichTextBox?

Lets say I have a RichTextBox (WPF) of 1000 words (English). Some words will be Bold, Underlined, Italic, and of different FontSizes. In other words, there are many element tags embedded within the FlowDocument.
Without knowing what the word is, how can I completely select the 13th word -- and only the 13th word, even if it has embedded element tags (say some characters are Bold, or Underlined, etc.)?
(I have not found any solution to this with Google and I am still finding the RichTextBox a rather difficult control to use).
Example: "This is a test."
Given: 3
Result: The TextRange of the word "test".
Any suggestions or ideas will be most appreciated.
TIA
Edit. It seems a loop will be needed :(. Anyway, this blog post was most helpful in answering this problem:Navigate Words in RichTextBox
Not very sure what you mean by embaded element tags, I gave it a try and here is how I did it :
string a = new TextRange(rtb.Document.ContentStart,
rtb.Document.ContentEnd).Text;
var b = a.Split(' ');
string On13th = b[12];
Let me know if I am not clear or you intended to achieve something else.

Fastest way to convert RTF to FlowDocument

What is the fastest way to convert a RTF to FlowDocument? I store RTF as plain string and then reload it back, I am using following method,
FlowDocument document = new FlowDocument();
document.SetValue(FlowDocument.TextAlignmentProperty, TextAlignment.Left);
TextRange content = new TextRange(document.ContentStart, document.ContentEnd);
if (content.CanLoad(DataFormats.Rtf) && string.IsNullOrEmpty(rtf) == false)
{
// If so then load it with RTF
byte[] valueArray = Encoding.ASCII.GetBytes(rtf);
using (MemoryStream stream = new MemoryStream(valueArray))
{
content.Load(stream, DataFormats.Rtf);
}
}
But this method is very slow. I need to load many RTFs (around 1000). What can be the trick to make the process fast? Is there any other way around to load a Flowdocument?
You really need to define what you actually need. TextBlock is not weak at all.
It has things to offer ;).
Colours(Background/Foreground + you can color specific part of TextBlock even)
Alignments(you can align TextBlocks as you want, and perhaps even part of them?! Not sure about the last one.
It has TextDecorations, which means it supports bold/italic/underline/strikethrough etc.
Fonts(yeah it supports custom fonts and whatever font you want)
But fair enough. I think you should store FlowDocument XAML instead of actual RTF. This way there will be no conversion and it should be multiple times faster. (See DataFormats.xaml)
Hello Vibhore the TextBlock element should be used when limited text support is required, Label can be used when minimal text support is required.
The FlowDocument element is a container for re-flowable documents that support rich presentation of content, and therefore, has a greater performance impact than using the TextBlock or Label controls.

flowdocument - inserting rich text at end creating extra paragraph breaks above insertion point

I am creating a flowdocument that consists of multiple records. Each record contains two tables at the top, and then some rich text that I'm pulling out of a database. The code that appends the rich text is found below (cp.Comments contains the rtf tagged text).
Dim tr As TextRange
Dim arr() As Byte
Using ms As New System.IO.MemoryStream
arr = (New System.Text.UTF8Encoding).GetBytes(cp.Comments)
ms.Write(arr, 0, arr.Length)
ms.Seek(0, IO.SeekOrigin.Begin)
tr = New TextRange(fd.ContentEnd, fd.ContentEnd) 'add to end
tr.Load(ms, DataFormats.Rtf)
End Using
The flowdocument renders the first of the records correctly, but all subsequent records are rendered with a break between the first and the second table. What is the most odd is that I'm rendering the 2 tables before importing the RTF, but the RTF is somehow affecting the spacing between the tables anyway.
fd = new FlowDocument
for each cp in SomeCollection
fdtemp = New FlowDocument
CreateFirstTable(cp, fdtemp)
CreateSecondTable(cp, fdtemp)
AddRTF(cp, fdtemp)
FlowDocumentUtils.AddDocument(fdtemp, fd)
next
The problem isn't something related to the data in the first element of the collection - if I tell the rendering to skip the rendering of the first record, then the second record renders ok, but the rest contain the extra spacing.
Note: the problem is definitely related to the rich text insertion - if I comment out the AddRTF call, then all the tables are correctly rendered smashed together. (table margins are all set to (0,0,0,0))
Has anyone ever seen this?
Have you checked out the solutions from this other question:
Adding text in a new line in WPF RichTextBox at runtime
Also, it appears that you have two separate methods:
CreateFirstTable(cp, fdtemp)
CreateSecondTable(cp, fdtemp)
I suspect that the difference between how these two methods are operating is where the problem is, but w/out knowing what they're really doing, I can only speculate.

WPF RichTextBox Control, How To Find All Italicized Words

How can you loop through all the "words" (spaces deliminate words) in an RTB (WPF Control) to see which ones are italicized?
thanks
Well, your task seems to be a quite complicated one.
The contents of a RichTextBox is a FlowDocument which can be found at the property Document. The FlowDocument, in turn, consists of several Blocks.
Each of the Blocks can be a Paragraph, a Section, a Table etc. You'll need to analyze each of them separately.
For the Paragraph, it consists of several Inlines, each of them can be a Span, which in turn may be an Italic. The Italic represents italicized text. The Italic can, in turn, have other inlines, containing other Spans (for example, Hyperlinks, which you may or may not want to include into your result).
You you basically need to traverse all the structure recursively and peek the text from your Italics. A special case may be the words where only a part is italicized, you'll need to have a strategy for them.
I am unaware of any easier methods to achieve what you want. HTH.
Edit:
Perhaps an easier alternate solution would be to traverse all the text using TextPointer from the beginning (richTextBox.Document.ContentStart), switching to the next position with position.GetNextContextPosition(LogicalDirection.Forward), and testing if your current position is inside an Italic using position.Parent. You should however care that Italic can be a non-immediate parent, so you'll perhaps need to traverse several parents upwards. Disclaimer: I did never try this idea in my code.
TextPointer tp = RTB.Document.ContentStart;
TextRange word = WordBreaker.GetWordRange(tp);
while (word.End.GetNextInsertionPosition(LogicalDirection.Forward) != null)
{
if (word.GetPropertyValue(TextElement.FontStyleProperty).ToString() == "Italic")
{
}
word = WordBreaker.GetWordRange(word.End.GetNextInsertionPosition(LogicalDirection.Forward));
}
}
with WordBreaker class from
Link

Silverlight 3 - Control over wrapping in TextBox

Ok I have the following problem in Silverlight. I have a control with 2 columns. On the left is a stack panel with line numbers and on the right is a textBox.
So when I write in textBox without wrapping turned on I can simply create the right count of numbers on the left, because I'm searching for '\r' in text.
But when I turn on wrapping I have no control over the count of lines in textBox.
Is there a way to get to that count? Or a way to know which line in textBox is going to wrap?
I hope you can understand what I'm trying to do.
There's one way to do this. You can simulate the word wrap operation in the background using a TextBlock. Here is a good link of the complete solution to this problem.
Extended TextBox control with MaxLines property
Is it not possible to create your items in code before they are passed to the view. This would enable you to bind a list of items to a listview and style them as you wish.
You need to user a value converter to count the number of char / lines and then trim that number if you wish to. Unless you use fixed width, you can't really count or calculte in advancet the size, since each application might be displayed differently (due to different sizing option).
There are two great sample chapters on Windows Phone and Silverlight for Windows Phone on the LearningWindosPhone.com site. There is great Windows Phone Trainng material , and dont forget the Windows Phone Develoeprs Blog
Yes there is a way to get the number of lines occupied by the text in the textbox. It's not that simple though 'coz you have to simulate the behavior of the word wrap in order to count/predict the number of lines generated as a result of a word wrap. I have the solution described here in detail.

Resources