
Automatic link highlighting in universal Windows applications
When developing a cross-platform application, the question arises of the unification of functionality between different platforms. When we were developing Edusty , we were faced with an unexpected problem for us - the lack of a built-in function for automatically highlighting links in text on Windows / Windows Phone platforms, which is present on Android and iOS platforms. Moreover - we did not find even third-party libraries that implement this functionality. I had to implement this functionality ourselves. What happened will be described in this article.

On the page where you want to display text with links, there is a RichTextBlock control. This control does not support MVVM data binding, so it was necessary to fill it out “the old fashioned way”.
There are three ways to fill RichTextBlock:
1. Static XAML markup directly in the page code.
2. Software filling in the BlockCollection .Blocks collection . Usually it is filled with objects of type Paragraph, which are initialized by objects that inherit the Inline class (for example, Run, Hyperlink, and so on).
3. As in the second case, filling in the Blocks collection, however, the formation of the Paragraph object occurs using the static XamlReader class from XAML markup (formed in a string form).
In this case, the third method will be the most optimal, since it allows you to form the layout as flexibly as possible. In order to parse the xaml string into objects, you must call the XamlReader.Load (xamlString) method. This method returns an object, which can be converted (in our case) to the Paragraph type and added to RichTextBlock.Blocks.
And so, we have an input line containing some text with or without links, and on the output you need to get a line with valid xaml markup for RichTextBlock (Paragraph tag), where all links would be in Hyperlink tags, and plain text in Run tags .
To do this, the entire text is divided into an array of words by spaces, then the output line begins to be formed in such a way that all tags are always closed with any input line.
1. At the very beginning of the text, an unclosed Run tag is added.
2. A cycle of words starts, where each word will be checked using a regular expression whether it is a link or not. If it is, then the Run tag is closed and the Hyperlink tag is inserted with the corresponding link, after which the Run tag opens again. If the current word is not a link, then simply write this word to the result and move on to the next word.
3. When all the words are sorted, you must close the Run tag.
Link processing is not as simple as it might seem at first glance. First, let's determine what links exist: with the protocol, without it, with a domain, with an IP address, with or without a port, with or without parameters.
In the source text, links can be either URL-encoded or not. In the latter case, they may contain characters that make xaml markup invalid , so the link must be processed using the Uri.EscapeUriString () method , which URL encodes only the link parameters, but not the protocol, domain or port. However, that is not all. URL encoding does not replace the '&' character, however this character also makes the xaml markup invalid, so it should be replaced with its html code '& amp;'.
Another feature of Windows platforms is that in order to open a link in another application, the OS looks at which application is installed by default for the protocol specified in this link (for example, htt: //), therefore, if no protocol is specified, open such a link The OS cannot (moreover, it will even throw a UriFormatException). So to any link where the protocol is not specified, you must add the default httr: // protocol.
The source text can sometimes contain various characters that violate the xaml markup, so it must be HTML-encoded before being placed in the Run tag using the WebUtility.HtmlEncode method .
After all this, a new line is formed, consisting of a Paragraph tag with the appropriate parameters and containing a set of tags formed earlier. Xaml markup is ready.

On the page where you want to display text with links, there is a RichTextBlock control. This control does not support MVVM data binding, so it was necessary to fill it out “the old fashioned way”.
There are three ways to fill RichTextBlock:
1. Static XAML markup directly in the page code.
2. Software filling in the BlockCollection .Blocks collection . Usually it is filled with objects of type Paragraph, which are initialized by objects that inherit the Inline class (for example, Run, Hyperlink, and so on).
3. As in the second case, filling in the Blocks collection, however, the formation of the Paragraph object occurs using the static XamlReader class from XAML markup (formed in a string form).
In this case, the third method will be the most optimal, since it allows you to form the layout as flexibly as possible. In order to parse the xaml string into objects, you must call the XamlReader.Load (xamlString) method. This method returns an object, which can be converted (in our case) to the Paragraph type and added to RichTextBlock.Blocks.
RTB.Blocks.Add((Paragraph)XamlReader.Load(xamlString));
XAML string generation
And so, we have an input line containing some text with or without links, and on the output you need to get a line with valid xaml markup for RichTextBlock (Paragraph tag), where all links would be in Hyperlink tags, and plain text in Run tags .
To do this, the entire text is divided into an array of words by spaces, then the output line begins to be formed in such a way that all tags are always closed with any input line.
1. At the very beginning of the text, an unclosed Run tag is added.
2. A cycle of words starts, where each word will be checked using a regular expression whether it is a link or not. If it is, then the Run tag is closed and the Hyperlink tag is inserted with the corresponding link, after which the Run tag opens again. If the current word is not a link, then simply write this word to the result and move on to the next word.
3. When all the words are sorted, you must close the Run tag.
Link processing is not as simple as it might seem at first glance. First, let's determine what links exist: with the protocol, without it, with a domain, with an IP address, with or without a port, with or without parameters.
In the source text, links can be either URL-encoded or not. In the latter case, they may contain characters that make xaml markup invalid , so the link must be processed using the Uri.EscapeUriString () method , which URL encodes only the link parameters, but not the protocol, domain or port. However, that is not all. URL encoding does not replace the '&' character, however this character also makes the xaml markup invalid, so it should be replaced with its html code '& amp;'.
Another feature of Windows platforms is that in order to open a link in another application, the OS looks at which application is installed by default for the protocol specified in this link (for example, htt: //), therefore, if no protocol is specified, open such a link The OS cannot (moreover, it will even throw a UriFormatException). So to any link where the protocol is not specified, you must add the default httr: // protocol.
The source text can sometimes contain various characters that violate the xaml markup, so it must be HTML-encoded before being placed in the Run tag using the WebUtility.HtmlEncode method .
After all this, a new line is formed, consisting of a Paragraph tag with the appropriate parameters and containing a set of tags formed earlier. Xaml markup is ready.
var words = source.Split(' ');
var sbInsideTags = new StringBuilder();
sbInsideTags.Append(@"");
sbInsideTags.Append(link);
sbInsideTags.Append(@" ");
sbXaml.Append(sbInsideTags);
sbXaml.Append(@" ""/>");
return sbXaml.ToString();