📜 ⬆️ ⬇️

Automatically highlight links in universal Windows applications

When developing a cross-platform application, the question arises about the unification of the functional between different platforms. When we were developing Edusty , we encountered an unexpected problem for us - the lack of a built-in feature for auto-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 by myself. That turned out, will be discussed in this article.




On the page where you need to display text with links, is located RichTextBlock control. This control does not support MVVM data binding, so it was necessary to fill it “in the old manner”.
')
<RichTextBlock Margin="20" x:Name="RTB" FontSize="20"/> 

There are three ways to fill out RichTextBlock:
1. Static XAML markup right in the page code.
2. Program filling in the BlockCollection .Blocks collection. Usually it is filled with objects of the Paragraph type, which are initialized by objects that inherit the Inline class (for example, Run, Hyperlink, and so on).
3. As in the second case, the Blocks collection is filled, however, the formation of the Paragraph object takes place with the help of the static XamlReader class from the XAML markup (formed in the form string).

In this case, the third method will be the most optimal, since it allows the most flexible formation of markup. In order to parse the xaml string into objects, you need to call the XamlReader.Load method (xamlString). This method returns an object, which can be cast (in our case) to the Paragraph type and added to RichTextBlock.Blocks.

 RTB.Blocks.Add((Paragraph)XamlReader.Load(xamlString)); 


Forming a XAML string



And so, we have an input string containing some text with or without links, and at the output you need to get a string with valid xaml markup for RichTextBlock (Paragraph tag), where all the 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 form so that all tags are always closed with any input line.
1. An unclosed Run tag is added to the very beginning of the text.
2. A loop starts by words, 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 is opened again. If the current word is not a link, then simply write the given word to the result and proceed to the next word.
3. When all words have been enumerated, it is necessary to close the Run tag.

With the processing of links is not so simple as it might seem at first glance. To begin with, we will determine which links are available: with the indication of the protocol, without it, with the domain, with the ip address, with or without the port, with or without parameters.
In the source code, links may or may not be URL-encoded. In the latter case, they may contain characters, because of which the xaml markup is not valid, so the link must be processed using the Uri.EscapeUriString () method, which URL-encodes only the parameters of the link, but not the protocol, domain or port. However, this is not all. URL-coding does not replace the '&' character, however, this character also makes xaml markup not valid, 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, https: //), therefore, if no protocol is specified, open such a link The OS cannot (moreover, it will even cause a UriFormatException exception). So to any link where the protocol is not specified, you need to add the default protocol http: //.

The source text can sometimes contain various characters that violate the xaml markup, so it must be HTML-encoded before being placed into the Run tag using the WebUtility.HtmlEncode method.

After all this, a new line is formed, consisting of the Paragraph tag with the corresponding parameters and containing the previously created set of tags. Xaml markup is ready.

 var words = source.Split(' '); var sbInsideTags = new StringBuilder(); sbInsideTags.Append(@"<Run Text="""); foreach (var word in words) { if (Regex.IsMatch(word, @"^((https?:\/\/)?(ftps?:\/\/)?[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[az]{2,6}(:[0-9]{1,5})?(\/\S*)?)")) { var link = word; link = link.Replace("&", "&amp;"); link = Uri.EscapeUriString(link); sbInsideTags.Append(@"""/> <Hyperlink NavigateUri="""); sbInsideTags.Append(link.Contains("://") ? link : "http://" + link); sbInsideTags.Append(@""">"); sbInsideTags.Append(link); sbInsideTags.Append(@"</Hyperlink> <Run Text="""); } else { sbInsideTags.Append(WebUtility.HtmlEncode(word)); sbInsideTags.Append(' '); } } var sbXaml = new StringBuilder(); sbXaml.Append(@"<Paragraph xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" TextAlignment=""Left"" FontSize=""20"" FontWeight=""Normal"" FontStyle=""Normal"" FontStretch=""Normal"" >"); sbXaml.Append(sbInsideTags); sbXaml.Append(@" ""/></Paragraph>"); return sbXaml.ToString(); 

Source: https://habr.com/ru/post/253635/


All Articles