I'm looking for a way to autodetect hyperlinks in RichTextBoxes in WPF (or if there is a smiliar control that's suitable for it, I'll take that...just needs to be a TextBox).
I'm aware of these solutions: - Clicking HyperLinks in a RichTextBox without holding down CTRL - WPF - WPF Dynamic HyperLinks RichTextbox
But my problem is, that I'm using two-way-binding in order to add dynamically RichTextBoxes to an ItemControl. My DataTemplate looks like this:
<RichTextBox IsDocumentEnabled="True" IsReadOnly="True">
<FlowDocument>
<Paragraph>
<Run Text="{Binding MyDataText}"/>
</Paragraph>
</FlowDocument>
</RichTextBox>
When I want to include clickable hyperlinks, I'd need to add them with
<Paragraph>
<Hyperlink>
https://stackoverflow.com
</Hyperlink>
<Paragraph>
But since I'm using data binding with only the text as shown above - and I'm tbh not aware of another solution - with the defined Data Template, I can't use that. The point is also that I need to mix normal text AND hyperlinks in one RichTextBox.
I'd appreciate any help, thanks!
You can use an attached property to enable data binding to the RichTextBox
. Then implement a IValueConverter
to convert from string
to the appropriate FlowDocument
after checking the type of the string
value:
RichTextBox.cs
public class RichTextBox : DependencyObject
{
public static readonly DependencyProperty DocumentSourceProperty = DependencyProperty.RegisterAttached(
"DocumentSource",
typeof(FlowDocument),
typeof(RichTextBox),
new PropertyMetadata(default(string), RichTextBox.OnDocumentSourceChanged));
public static void SetText([NotNull] DependencyObject attachingElement, FlowDocument value) =>
attachingElement.SetValue(RichTextBox.DocumentSourceProperty, value);
public static string GetText([NotNull] DependencyObject attachingElement) =>
(FlowDocument) attachingElement.GetValue(RichTextBox.DocumentSourceProperty);
private static void OnDocumentSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (!(d is System.Windows.Controls.RichTextBox richTextBox))
{
throw new ArgumentException($"Wrong type.\nThe attaching element must be of type {typeof(System.Windows.Controls.RichTextBox)}.");
}
Application.Current.Dispatcher.InvokeAsync(
() => richTextBox.Document = (FlowDocument) e.NewValue,
DispatcherPriority.DataBind);
}
}
StringToFlowDocumentConverter.cs
[ValueConversion(typeof(string), typeof(FlowDocument))]
public class StringToFlowDocumentConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is string stringValue)
{
return stringValue.StartsWith("http", StringComparison.OrdinalIgnoreCase)
? CreateHyperlinkDocument(stringValue)
: CreateTextDocument(stringValue);
}
return Binding.DoNothing;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
private FlowDocument CreateHyperlinkDocument(string url)
{
return new FlowDocument(new Paragraph(new Hyperlink(new Run(url))));
}
private FlowDocument CreateTextDocument(string text)
{
return new FlowDocument(new Paragraph(new Run(text)));
}
}
MainWindow.xaml
<Window>
<Window.Resources>
<StringToFlowDocumentConverter x:Key="StringToFlowDocumentConverter" />
</Window.Resources>
<RichTextBox RichTextBox.DocumentSource="{Binding MyDataText, Converter={StaticResource StringToFlowDocumentConverter}" />
</Window>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.