I\'ve got a bit of text that I\'m trying to display in a list. Some of those pieces of a text contain a hyperlink. I\'d like to make the links clickable within the text.
The VB.Net version of Bojan's answer. I improved a little upon it: This code will parse an url like http://support.mycompany.com?username=x&password=y to an inline of http://support.mycompany.com, while still navigating to the full url with username and password
Imports System.Text.RegularExpressions
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Documents
Public Class NavigationService
' Copied from http://geekswithblogs.net/casualjim/archive/2005/12/01/61722.aspx '
Private Shared ReadOnly RE_URL = New Regex("(?#Protocol)(?(?:(?:ht|f)tp(?:s?)\:\/\/|~/|/)?(?#Username:Password)(?:\w+:\w+@)?(?#Subdomains)(?:(?:[-\w]+\.)+(?#TopLevel Domains)(?:com|org|net|gov|mil|biz|info|mobi|name|aero|jobs|museum|travel|[a-z]{2})))(?#Port)(?::[\d]{1,5})?(?#Directories)(?:(?:(?:/(?:[-\w~!$+|.,=]|%[a-f\d]{2})+)+|/)+|\?|#)?(?#Query)(?:(?:\?(?:[-\w~!$+|.,*:]|%[a-f\d{2}])+=(?:[-\w~!$+|.,*:=]|%[a-f\d]{2})*)(?:&(?:[-\w~!$+|.,*:]|%[a-f\d{2}])+=(?:[-\w~!$+|.,*:=]|%[a-f\d]{2})*)*)*(?#Anchor)(?:#(?:[-\w~!$+|.,*:=]|%[a-f\d]{2})*)?")
Public Shared ReadOnly TextProperty = DependencyProperty.RegisterAttached( _
"Text",
GetType(String),
GetType(NavigationService),
New PropertyMetadata(Nothing, AddressOf OnTextChanged)
)
Public Shared Function GetText(d As DependencyObject) As String
Return TryCast(d.GetValue(TextProperty), String)
End Function
Public Shared Sub SetText(d As DependencyObject, value As String)
d.SetValue(TextProperty, value)
End Sub
Private Shared Sub OnTextChanged(d As DependencyObject, e As DependencyPropertyChangedEventArgs)
Dim text_block = TryCast(d, TextBlock)
If text_block Is Nothing Then Return
text_block.Inlines.Clear()
Dim new_text = CStr(e.NewValue)
If String.IsNullOrEmpty(new_text) Then Return
' Find all URLs using a regular expression '
Dim last_pos As Integer = 0
For Each match As Match In RE_URL.Matches(new_text)
'Copy raw string from the last position up to the match '
If match.Index <> last_pos Then
Dim raw_text = new_text.Substring(last_pos, match.Index - last_pos)
text_block.Inlines.Add(New Run(raw_text))
End If
' Create a hyperlink for the match '
Dim link = New Hyperlink(New Run(match.Groups("domainURL").Value)) With
{
.NavigateUri = New Uri(match.Value)
}
AddHandler link.Click, AddressOf OnUrlClick
text_block.Inlines.Add(link)
'Update the last matched position '
last_pos = match.Index + match.Length
Next
' Finally, copy the remainder of the string '
If last_pos < new_text.Length Then
text_block.Inlines.Add(New Run(new_text.Substring(last_pos)))
End If
End Sub
Private Shared Sub OnUrlClick(sender As Object, e As RoutedEventArgs)
Try
Dim link = CType(sender, Hyperlink)
Process.Start(link.NavigateUri.ToString)
Catch
End Try
End Sub
End Class