FlowDocument alternative in wp8 or Hyperlinks and Run on same line - c#

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/

Related

Automatic highlighting a part of the text in a TextBox or RichTextBox

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!

WPF Sending chat message which contains a hyperlink

I have a small problem, I have created a private chat message system using c#. Now what I need is a way to send a clickable link to other person.
When selecting a person from the list, I press invite button and a message comes to the messagebox like "to User1: join from this link"
private void InvBtn_Click(object sender, RoutedEventArgs e)
{
selectedUser = UsersListBox.SelectedItem.ToString();
if (selectedUser != login)
{
MessageBox.Show("Select other user than yourself");
return;
}
else
{
Msg.Text = selectedUser + " join from this 'link' ";
}
}
After sending the other person gets the message to RichTextBox saying
From user2: join from this link
There is no need for open a website, but other other form where will be more details.
You need to create custom MessageBox with Hyperlink button.
Try this out, here u need to set the height and width property properly....and make the constructor to accept the arguments so that users can design it the way they want.
public class CustomMessageBox
{
public CustomMessageBox()
{
Window w = new Window();
DockPanel panel = new DockPanel();
TextBlock tx = new TextBlock();
Paragraph parx = new Paragraph();
Run run1 = new Run("Text preceeding the hyperlink.");
Run run2 = new Run("Text following the hyperlink.");
Run run3 = new Run("Link Text.");
Hyperlink hyperl = new Hyperlink(run3);
hyperl.NavigateUri = new Uri("http://search.msn.com");
tx.Inlines.Add(hyperl);
panel.Children.Add(tx);
w.Content = panel;
w.Show();
}
}
Source : https://social.msdn.microsoft.com/Forums/vstudio/en-US/57fcd28b-6e9e-4529-a583-892c8f6d7cc8/hyperlink-in-wpf-message-box?forum=wpf
First you need to come up with a way to include your special markup in the text message. You can either pack the entire message in an existing container format (XML, JSON, etc.) or to keep things simple include special markers within the text, for example:
Hi User1, join from [This link:12345].
The same way you could include markup for other things like bold (**bold**), italics (*italics*), or actual hyperlinks to websites.
On the other side, you will need a parser that detects this special markup and replaces it with a clickable link. In the following example I'm using Regex to find and replace all text in the format [Text:Command].
private IEnumerable<Inline> Parse(string text)
{
// Define the format of "special" message segments
Regex commandFinder = new Regex(#"\[(?<text>.+)\:(?<command>.+)]");
// Find all matches in the message text
var matches = commandFinder.Matches(text);
// remember where to split the string so we don't lose other
// parts of the message
int previousMatchEnd = 0;
// loop over all matches
foreach (Match match in matches)
{
// extract the text fore it
string textBeforeMatch = text.Substring(previousMatchEnd, match.Index - previousMatchEnd);
yield return new Run(textBeforeMatch);
previousMatchEnd = match.Index + match.Length;
// extract information and create a clickable link
string commandText = match.Groups["text"].Value;
string command = match.Groups["command"].Value;
// it would be better to use the "Command" property here,
// but for a quick demo this will do
Hyperlink link = new Hyperlink(new Run(commandText));
link.Click += (s, a) => { HandleCommand(command); };
yield return link;
}
// return the rest of the message (or all of it if there was no match)
if (previousMatchEnd < text.Length)
yield return new Run(text.Substring(previousMatchEnd));
}
In the method where you receive the message, you can simply integrate it like this:
// Where you receive the text
// This probably is just a `txtOutput.Text += ` until now
private void OnTextReceived(string text)
{
txtOutput.Inlines.AddRange(Parse(text));
}
// the method that gets invoked when a link is clicked
// and you can parse/handle the actual command
private void HandleCommand(string command)
{
MessageBox.Show("Command clicked: " + command);
}
The message Hi User1, join from [this link:1234567890] will show up as Hi User1, join from this link and will invoke HandleCommand("1234567890") when clicked.

RichtextBox editing inline

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());

Finding & Replacing text in a MS Word textbox

I am trying to replace the temporary text in a word document with new text from a list. It works if the text is not in a shape, but once it tries to find the text in a textbox it throws an error. Here is what I have so far:
public void FindReplace(List<repvals> replaceVals, string docLocation, int listLen)
{
//Opens a new Word application
var app = new Microsoft.Office.Interop.Word.Application();
//Opens the .docx
var doc = app.Documents.Open(docLocation, true, false);
//Selects the document
var range = doc.Range();
for (int i = 0; i < listLen; i++)
{
//Finds the parameter, then replaces
range.Find.Execute(FindText: Convert.ToString(replaceVals[i].tempVal), Replace: WdReplace.wdReplaceAll, ReplaceWith: Convert.ToString(replaceVals[i].Boxes));
var shapes = doc.Shapes;
//Finds text within textboxes, then changes them
foreach (Microsoft.Office.Interop.Word.Shape shape in shapes)
{
var initialText = shape.TextFrame.TextRange.Text;
var resultingText = initialText.Replace(Convert.ToString(replaceVals[i].tempVal), Convert.ToString(replaceVals[i].Boxes));
shape.TextFrame.TextRange.Text = resultingText;
}
}
//prints document
doc.Save();
doc.Close();
//fully closes Word
Marshal.ReleaseComObject(app);
}
The problem occurs when it hits
var initialText = shape.TextFrame.TextRange.Text;
And throws an error saying: "This object does not support attached text."
The text in the shapes are nothing special. (e.g. tDATE, tNAME, etc.)
Any ideas?
I found the answer. Turns out my code was fine, however the document I was using (which I didn't write), had another shape on the second to last page to form a place to sign your name. I replaced that with an underscore, ran the code, and everything changed perfectly.
For those who also experience this problem, try checking how many shapes your foreach loop has counted:
http://i.imgur.com/1yNrL4p.png
Thank you Andrew and varocarbas for the help
*"In 2003 the AltText default for a standard textbox WAS the contained text BUT since you can change the Alt Text to NOT match it was never a good idea to read it this way. In 2010 the default for Alt Text is blank
If the textbox is named "Text Box 2" (substitute the correct name if not)
MsgBox ActiveDocument.Shapes("Text Box 2").TextFrame.TextRange should work."*
--
John SR Wilson
http://answers.microsoft.com/en-us/office/forum/office_2010-customize/shapesalternativetext-is-blank-for-the-docx/7671c746-2c2b-41d9-b7de-389a766587a7?page=2&msgId=31041d67-e62b-4ce0-b283-57fd6a4ff6b2

How to bring Inline from a RichTextBox Child into View

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

Categories

Resources