using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Media; namespace Juick.Controls { public class HyperLinkRichTextBox : RichTextBox { static readonly Regex UrlRegex = new Regex(@"http(s)?://([\w+?\.\w+])+([a-zA-Z0-9\~\!\@\#\$\%\^\&\*\(\)_\-\=\+\\\/\?\.\:\;\'\,]*)?", RegexOptions.Compiled); // TODO: Add more entities static readonly Regex JuickEntityRegex = new Regex(@"#(\d+)(/\d+)?", RegexOptions.Compiled); public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(HyperLinkRichTextBox), new PropertyMetadata(default(string), TextPropertyChanged)); public string Text { get { return (string)GetValue(TextProperty); } set { SetValue(TextProperty, value); } } private static void TextPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs) { var richTextBox = (HyperLinkRichTextBox)dependencyObject; var stringValue = (string)dependencyPropertyChangedEventArgs.NewValue; var paragraph = new Paragraph(); var index = 0; foreach (var match in UrlRegex.Matches(stringValue).OfType().Union(JuickEntityRegex.Matches(stringValue).OfType())) { Uri uri = null; if (!Uri.TryCreate(match.Value, UriKind.Absolute, out uri)) { // Juick entity uri = new Uri(string.Format("/ThreadView.xaml?mid={0}", JuickEntityRegex.Replace(match.Value, "$1")), UriKind.Relative); } if (match.Index > 0) { var length = match.Index - index; if (length > 0) { paragraph.Inlines.Add(new Run { Text = stringValue.Substring(index, length) }); } } var hyperLink = new Hyperlink { NavigateUri = uri }; if (uri.IsAbsoluteUri) { hyperLink.TargetName = "_blank"; hyperLink.Inlines.Add(uri.Host); } else { hyperLink.Inlines.Add(match.Value); } paragraph.Inlines.Add(hyperLink); index = match.Index + match.Length; } if (index == 0 || index < stringValue.Length - 1) { var lastRunText = stringValue.Substring(index); if (lastRunText.Length > 0) { paragraph.Inlines.Add(new Run { Text = lastRunText }); } } richTextBox.Blocks.Clear(); richTextBox.Blocks.Add(paragraph); } } }