there is no way to know which link the user touched but only it touched the TextBlock somewhere.<\/strong><\/p>\n#fail 4 : use a RichTextBlock with InlineUIContainer and an HyperlinkButton element<\/h3>\n
After these failures, I decided to use a weapon of mass destruction : a RichTextBlock and a InlineUIContainer element.
\nYou can’t just add Run inside a RichTextBlock but instead, you have to create one (or more) root paragraph element.<\/p>\n
The InlineUIContainer lets you put any FrameworkElement you want inside a document(the content of the Paragraph). You can then register handlers to the events of this FrameworkElements as you would have in any Xaml UI. <\/p>\n
In the code snippet below, I register myself to Tapped event of the Textblock I insert in my paragraph :
\n[xml]
\n<RichTextBlock IsTextSelectionEnabled="False">
\n <Paragraph>
\n <Run Text="Cupcake ipsum dolor. Sit amet I love croissant fawork" \/>
\n <Run Text=". " \/><\/p>\n
<InlineUIContainer>
\n <Border Background="#FFF1EFEF">
\n <TextBlock Tapped="OnLinkTapped" Foreground="#FFFF1BF5"
\n TextWrapping="Wrap"> <Underline>
\n <Run Text="I love ice cream, to write very long text " \/>
\n <Run Text="and to take some screenshots." \/>
\n <\/Underline>
\n <\/TextBlock>
\n <\/Border>
\n <\/InlineUIContainer><\/p>\n
<Run Text="A Chocolate ice cream souffl\u00e9 pastry. " \/>
\n <Run Text="Bear claw chocolate tart brownie apple pie." \/>
\n <\/Paragraph>
\n<\/RichTextBlock>
\n[\/xml]<\/p>\n
Wonderful… wait … oh no… there is still one issue : the paragraph element will consider the InlineUIContainer as “whole block” and not as “text” and then it will wrap strangely<\/i> your content.<\/strong> In this screenshot, I added a gray border around my TextBlock show this behavior to you :
\n<\/p>\n#Success : use a RichTextBlock and the GetPositionFromPoint method<\/h3>\n
I finally found one hack and if you know a better way, please tell me in the comment which one it is \ud83d\ude42<\/p>\n
My solution is to use the RichTextBlock’s tapped event and its GetPositionFromPoint method<\/strong>. This method returns a TextPointer for a given position of your RichTextBlock. This TextPointer object has a Parent property which is the TextElement (Run, Underline, Span, etc…) the user clicked on : exactly what we want !<\/p>\nMy Xaml then look like this :
\n[xml]<RichTextBlock IsTextSelectionEnabled="False"
\n Margin="30"
\n Width="600"
\n TextAlignment="Justify"
\n FontSize="40"
\n TextWrapping="Wrap"
\n Tapped="UIElement_OnTapped">
\n <Paragraph>
\n <Run Text="Cupcake ipsum dolor. Sit amet I love croissant fawork" \/>
\n <Run Text=". " \/><\/p>\n
<Underline x:Name="LinkToInfiniteSquare"
\n Foreground="#FFFF1BF5">
\n <Run Text="I love ice cream, to write very long text " \/>
\n <Run Text="and to take some screenshots." \/>
\n <\/Underline><\/p>\n
<Run Text="A Chocolate ice cream souffl\u00e9 pastry. " \/><\/p>\n
<Underline x:Name="LinkToMyBlog"
\n Foreground="#FFFF1BF5">
\n <Run Text="Bear claw chocolate tart brownie apple pie." \/>
\n <\/Underline><\/p>\n
<\/Paragraph>
\n<\/RichTextBlock><\/p>\n
[\/xml]<\/p>\n
The last part is to walk trough the parents of the clicked\/touched element to find out its Underline parent, read its name and launch the correct action<\/strong>.<\/p>\n[csharp]
\nprivate void UIElement_OnTapped(object sender, TappedRoutedEventArgs e)
\n{
\n var richTB = sender as RichTextBlock;
\n var textPointer = richTB.GetPositionFromPoint(e.GetPosition(richTB));<\/p>\n
var element = textPointer.Parent as TextElement;
\n while (element != null && !(element is Underline))
\n {
\n if (element.ContentStart != null
\n && element != element.ElementStart.Parent)
\n {
\n element = element.ElementStart.Parent as TextElement;
\n }
\n else
\n {
\n element = null;
\n }
\n }<\/p>\n
if (element == null) return;<\/p>\n
var underline = element as Underline;
\n if (underline.Name == "LinkToInfiniteSquare")
\n {
\n Launcher.LaunchUriAsync(new Uri("http:\/\/www.infinitesquare.com"));
\n }
\n else if (underline.Name == "LinkToMyBlog")
\n {
\n Launcher.LaunchUriAsync(new Uri("http:\/\/www.jonathanantoine.com"));
\n }<\/p>\n
}<\/p>\n
[\/csharp]<\/p>\n
By the way, I can not use a TextBlock element because it does not have the GetPositionFromPoint method.<\/p>\n
Do you know a better way ?<\/h3>\n
(Please don’t tell me to do it in HTML\/JS :p)<\/p>\n
The source code is available here<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"Xaml is really powerful and you can build nearly any user interface you want with it. However it can be hard sometimes and in this post I will describe how you can create something I…<\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[35,5],"tags":[14,15,30,34,25,40,24,31],"_links":{"self":[{"href":"http:\/\/www.jonathanantoine.com\/wp-json\/wp\/v2\/posts\/1424"}],"collection":[{"href":"http:\/\/www.jonathanantoine.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.jonathanantoine.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.jonathanantoine.com\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"http:\/\/www.jonathanantoine.com\/wp-json\/wp\/v2\/comments?post=1424"}],"version-history":[{"count":18,"href":"http:\/\/www.jonathanantoine.com\/wp-json\/wp\/v2\/posts\/1424\/revisions"}],"predecessor-version":[{"id":1444,"href":"http:\/\/www.jonathanantoine.com\/wp-json\/wp\/v2\/posts\/1424\/revisions\/1444"}],"wp:attachment":[{"href":"http:\/\/www.jonathanantoine.com\/wp-json\/wp\/v2\/media?parent=1424"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.jonathanantoine.com\/wp-json\/wp\/v2\/categories?post=1424"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.jonathanantoine.com\/wp-json\/wp\/v2\/tags?post=1424"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}