I have an array of sentences. Every sentence is a new Run object inside Inlines property of richtextbox`s FlowDocument.
Every sentence have a color.
var paragraph = new Paragraph();
foreach (var sentence in Sentences)
{
....
paragraph.Inlines.Add(new Run { Text = sentence, Background = new SolidColorBrush(color) });
}
tbText.Document.Blocks.Add(paragraph);
When I am editing the sentence like this (I changed 'yes' to 'y1111111111111es' )
I expected to get the same Run object with changed text from 'yes' to 'y1111111111111es' but instead I got 3 Run objects with 'y', '1111111111111111111' and 'es'
That`s how I retrieve the textes
foreach (Paragraph paragraph in tbText.Document.Blocks)
{
foreach (Run inline in paragraph.Inlines)
{
editedTextes.Add(inline.Text);
}
}
Is there any way to edit the text inside native Run object without populating new Run objects when I change the text
It seems FlowDocument dynamically adds runs to encourage wrapping by design.
I see from another stackoverflow post, that if you use a TextBlock instead of runs inside of Paragraphs, you can preserve your text and remove the runs and prevent wrapping.
Try this in your second block:
foreach (Paragraph paragraph in tbText.Document.Blocks)
{
var sb = new StringBuilder();
foreach (Run inline in paragraph.Inlines)
{
sb.Append(inline.Text);
}
editedTextes.Add(new TextBlock()
{
Text = sb.ToString(),
TextWrapping = TextWrapping.NoWrap
});
}
Or just add one run after you have built the string if you don't like the TextBlocks:
editedTextes.Add(sb.ToString());
Related
Is it possible to highlight a part of a text without selecting this part of the text preferably with a different color in Textbox or Rich TextBox? In fact, I mean, a part of the text is highlighted by another color differing from the color assigned for text selection. To clarify, I have attached an image showing this behavior. (The image is from a website, not WPF).
The bold and dark green part is a text which is just highlighted, and the gray region is a selected part.
Using the RichTextBox element allows for more styling options which, to my knowledge, aren't available for the regular TextBox element.
Here is an approach that I have created:
// Generate example content
FlowDocument doc = new FlowDocument();
Run runStart = new Run("This is an example of ");
Run runHighlight = new Run("text highlighting in WPF");
Run runEnd = new Run(" using the RichTextBox element.");
// Apply highlight style
runHighlight.FontWeight = FontWeights.Bold;
runHighlight.Background = Brushes.LightGreen;
// Create paragraph
Paragraph paragraph = new Paragraph();
paragraph.Inlines.Add(runStart);
paragraph.Inlines.Add(runHighlight);
paragraph.Inlines.Add(runEnd);
// Add the paragraph to the FlowDocument
doc.Blocks.Add(paragraph);
// Apply to RichTextBox
YourRichTextBoxHere.Document = doc;
View Screenshot
I found this article to be helpful.
Highlight Searched Text in WPF ListView
While the article is about highlighting searched text in a ListView, I have easily adapted it in my own code to work with pretty much any control.
Starting with the control you pass in, it will recursively look for TextBlocks and will find the text you want, extract it as an inline, and will change it's Background / Foreground properties.
You can easily adapt the code to be a behavior if your want.
Here is an example:
private void HighlightText(object controlToHighlight, string textToHighlight)
{
if (controlToHighlight == null) return;
if (controlToHighlight is TextBlock tb)
{
var regex = new Regex("(" + textToHighlight + ")", RegexOptions.IgnoreCase);
if (textToHighlight.Length == 0)
{
var str = tb.Text;
tb.Inlines.Clear();
tb.Inlines.Add(str);
return;
}
var substrings = regex.Split(tb.Text);
tb.Inlines.Clear();
foreach (var item in substrings)
{
if (regex.Match(item).Success)
{
var run = new Run(item)
{
Background = (SolidColorBrush) new BrushConverter().ConvertFrom("#FFFFF45E")
};
tb.Inlines.Add(run);
}
else
{
tb.Inlines.Add(item);
}
}
}
else
{
if (!(controlToHighlight is DependencyObject dependencyObject)) return;
for (var i = 0; i < VisualTreeHelper.GetChildrenCount(dependencyObject); i++)
{
HighlightText(VisualTreeHelper.GetChild(dependencyObject, i), textToHighlight);
}
}
}
I hope this is helpful!
I'm very new to wpf and I would like to make a text analysing tool.
I already know how to import text into rich textbox and format it properly, but now I want to run a method that extracts all lines in the flowdocument that start with INT or EXT and place them in a listbox. It seems to be quite easier to do this in winforms than in WPF.
Is there someone who can guide me with this?
I wish I could already provide some code but the flowdocument is new to me as is wpf.
I have written a code snippet to collect the lines that begin with INT or EXT.
I am sure the code is not optimal, because i am not practised with RichTextBox, but i think it is very easy to understand.
private List<string> CollectLines()
{
TextRange textRange = new TextRange(
// TextPointer to the start of content in the RichTextBox.
TestRichTextBox.Document.ContentStart,
// TextPointer to the end of content in the RichTextBox.
TestRichTextBox.Document.ContentEnd);
// The Text property on a TextRange object returns a string
// representing the plain text content of the TextRange.
var text = textRange.Text;
List<string> resultList = new List<string>();
// Collect all line that begin with INT or EXT
// Or use .Contains if the line could begin with a tab (\t), spacing or whatever
using (StringReader sr = new StringReader(text))
{
var line = sr.ReadLine();
while (line != null)
{
if (line.StartsWith("INT") || line.StartsWith("EXT"))
{
resultList.Add(line);
}
line = sr.ReadLine();
}
}
return resultList;
}
Maybe you can find out how you can put the list into a listbox yourself :)
I have a text with hyperlinks in it.
To not irritate the reader I want to have the normal text and the links on the same line. Right now every Inline element starts a new line.
It displays:
Please visit
http://google.com
to continue.
I want:
Please visit http://google.com to continue.
I've also noticed, that the hyperlink Hit area cover the hole inline element and not just the text.
My problem is identical than described and solved here:
Add clickable hyperlinks to a RichTextBox without new paragraph
The problem is, that it seems than something like a flowdocument for wp8 doesn't exist.
I need to create the inline elements programatically.
EDIT 1:
Here my code how I add the inline elements:
int index = 0;
rt = new RichTextBox() { };
while (true)
{
Paragraph para = new Paragraph();
if (item.text.Substring(index).IndexOf("<") == 0)
{
//TRUE when link
//I extract the URL and the linktext, and also update the index
Hyperlink hyper = new Hyperlink();
hyper.Click += new RoutedEventHandler((sender,e) => Hyperlink_Click(sender,e,URL));
hyper.Inlines.Add(linktext);
para.Inlines.Add(hyper);
}
else if (item.text.Substring(index).Contains("<"))
{
//TRUE when text, item.text contains a link
// I extract the text and update index
Run run = new Run() { Text = text };
para.Inlines.Add(run);
}
else
{
//TRUE when only text is left
Run run = new Run() { Text = item.text.Substring(index) };
para.Inlines.Add(run);
rt.Blocks.Add(para);
break;
}
// REMOVE: rt.Blocks.Add(para);
}
rt.SetValue(Grid.RowProperty, MainViewer.RowDefinitions.Count - 1);
MainViewer.Children.Add(rt);
EDIT 2
I still couldn't solve this Problem, does no one know a solution? I saw what I want in an App before, so it must be possible.
EDIT 3
I've created for every inline element a new paragraph. I've fixed my code above, it is working now
Paragraph p = new Paragraph();
p.Inlines.Add("Plase visit ");
var link = new Hyperlink();
link.Inlines.Add("google.com ");
p.Inlines.Add(link);
p.Inlines.Add("to continue");
rtb.Blocks.Add(p);
this works fine for me.
PS
If you want to show some html in you app, you can use HTMLTextBox or HTMLViewer from http://msptoolkit.codeplex.com/
How can i focus a Inline in a RichTextBox?
I Create a FlowDocument from a Text-File and load it in my richTextBox1
and mark one Inline after an other accordingly to a Button_click (be recreating the FlowDocument)
with this code:
richTextBox1.SelectAll();
richTextBox1.Selection.Text = "";
string text = System.IO.File.ReadAllText(file);
int iZeile = 0;
string[] split = text.Split(new string[] {"\r\n"},StringSplitOptions.None);
foreach (string s in split)
{
if (iZeile != 27)
{
paragraph.Inlines.Add(s + "\r\n"); // adds line added without marking
}
else
{
Run run = new Run(split[27]); // adds line with marking
run.Background = Brushes.Yellow;
paragraph.Inlines.Add(run);
paragraph.Inlines.Add("\r\n");
}
iZeile++;
}
FlowDocument document = new FlowDocument(paragraph);
richTextBox1.Document = new FlowDocument();
richTextBox1.Document = document;
Keyboard.Focus(richTextBox1);
}
I know its not.. perfect.
the Issue
It works so far but the problem that occurs is me Market Inline doesn't comes intoView. Is there a easy way to bring this Inline intoView?
The straightforward solution seemed to be FrameworkContentElement.BringIntoView() but after putting it in the code below it initially had no effect. As it turns out this is one of these timing issues (I've seen similar problems in WinForms) that can be solved by processing the outstanding Windows Messages. WPF has no direct equivalent of DoEvents() but there exists a well known substitute.
I placed this in a ButtonClick, changes marked with //**:
Paragraph paragraph = new Paragraph();
Inline selected = null; //**
richTextBox1.SelectAll();
richTextBox1.Selection.Text = "";
string text = System.IO.File.ReadAllText(#"..\..\MainWindow.xaml.cs");
int iZeile = 0;
string[] split = text.Split(new string[] { "\r\n" }, StringSplitOptions.None);
foreach (string s in split)
{
if (iZeile != 27)
{
paragraph.Inlines.Add(s + "\r\n"); // adds line added without marking
}
else
{
Run run = new Run(split[27]); // adds line with marking
run.Background = Brushes.Yellow;
paragraph.Inlines.Add(run);
paragraph.Inlines.Add("\r\n");
selected = run; // ** remember this element
}
iZeile++;
}
FlowDocument document = new FlowDocument(paragraph);
richTextBox1.Document = new FlowDocument();
richTextBox1.Document = document;
Keyboard.Focus(richTextBox1);
DoEvents(); // ** this is required, probably a bug
selected.BringIntoView(); // **
And the helper method, from here:
public static void DoEvents()
{
Application.Current.Dispatcher.Invoke(
System.Windows.Threading.DispatcherPriority.Background,
new Action(delegate { }));
}
you should try one of this methods
richTextBox.SelectionStart = richTextBox.Text.Length;
richTextBox.ScrollToCaret();
.
richTextBox.AppendText(text);
richTextBox.ScrollToEnd();
futher informations are here and here
Edit
ok after a bit of digging in the WPF RichTextBox i thing you cloud try richTextBox.ScrollToVerticalOffset(Offset)
to get the Offset maybe you could use this answer
EDIT 2
ok after some more research i found following Link where you can download this working example
StringBuilder sb = new StringBuilder();
sb.Append(
string.Format("{0} |{1} ", Name, Value)
);
Display.Text = sb.ToString(); // Display is a WP7 TextBlock control
I want to make "Name" as bold. Is it possible to do that ?
ChrisF offers the RichTextBox as a solution but its less well known that simple font variation is acheivable with the simple TextBlock:-
myTextBlock.Inlines.Add(new Run() { Text = "Hello " });
myTextBlock.Inlines.Add(new Run() { Text = "World", FontWeight= FontWeights.Bold });
A StringBuilder only contains character data, not formatting. You can't, basically. Unless you are actually generating html or rtf etc.
In the same way that notepad.exe doesn't have bold/italics/etc.
I'm not a WP7 expert, but maybe there is a different control you can use here, more aimed at formatted text.
You'll need to put the text into a RichTextBox and have the name as a separate Run in the Paragraph as in this example from the MSDN:
// Create a Run of plain text and some bold text.
Run myRun1 = new Run();
myRun1.Text = "A RichTextBox with ";
Bold myBold = new Bold();
myBold.Inlines.Add("initial content ");
Run myRun2 = new Run();
myRun2.Text = "in it.";
// Create a paragraph and add the Run and Bold to it.
Paragraph myParagraph = new Paragraph();
myParagraph.Inlines.Add(myRun1);
myParagraph.Inlines.Add(myBold);
myParagraph.Inlines.Add(myRun2);
// Add the paragraph to the RichTextBox.
MyRTB.Blocks.Add(myParagraph);