Add Hyperlink to Textblock Wpf

Add hyperlink to textblock WPF

You can use Regex with a value converter in such situation.

Use this for your requirements (original idea from here):

    private Regex regex = 
new Regex(@"\[a\s+href='(?<link>[^']+)'\](?<text>.*?)\[/a\]",
RegexOptions.Compiled);

This will match all links in your string containing links, and make 2 named groups for each match : link and text

Now you can iterate through all the matches. Each match will give you a

    foreach (Match match in regex.Matches(stringContainingLinks))
{
string link = match.Groups["link"].Value;
int link_start = match.Groups["link"].Index;
int link_end = match.Groups["link"].Index + link.Length;

string text = match.Groups["text"].Value;
int text_start = match.Groups["text"].Index;
int text_end = match.Groups["text"].Index + text.Length;

// do whatever you want with stringContainingLinks.
// In particular, remove whole `match` ie [a href='...']...[/a]
// and instead put HyperLink with `NavigateUri = link` and
// `Inlines.Add(text)`
// See the answer by Stanislav Kniazev for how to do this
}

Note : use this logic in your custom ConvertToHyperlinkedText value converter.

Create Hyperlink in TextBlock via Binding

To do what you want you will have to use Inlines property of your TextBlock, but as it's not a DependencyProperty, it cannot be a target of binding. We will have to extend your TextBlock class, but as it's sealed we will have to use other class.

Lets define static class, which will add apropriate Inline - Hyperlink or Run, depending on Regex match. It can look for example like this:

public static class TextBlockExtension
{
public static string GetFormattedText(DependencyObject obj)
{ return (string)obj.GetValue(FormattedTextProperty); }

public static void SetFormattedText(DependencyObject obj, string value)
{ obj.SetValue(FormattedTextProperty, value); }

public static readonly DependencyProperty FormattedTextProperty =
DependencyProperty.Register("FormattedText", typeof(string), typeof(TextBlockExtension),
new PropertyMetadata(string.Empty, (sender, e) =>
{
string text = e.NewValue as string;
var textBl = sender as TextBlock;
if (textBl != null)
{
textBl.Inlines.Clear();
Regex regx = new Regex(@"(http://[^\s]+)", RegexOptions.IgnoreCase);
var str = regx.Split(text);
for (int i = 0; i < str.Length; i++)
if (i % 2 == 0)
textBl.Inlines.Add(new Run { Text = str[i] });
else
{
Hyperlink link = new Hyperlink { NavigateUri = new Uri(str[i]), Foreground = Application.Current.Resources["PhoneAccentBrush"] as SolidColorBrush };
link.Inlines.Add(new Run { Text = str[i] });
textBl.Inlines.Add(link);
}
}
}));
}

Then in XAML we use it just like this:

<TextBlock local:TextBlockExtension.FormattedText="{Binding MyText}" FontSize="15"/>

And after putting some text to my property:

private void firstBtn_Click(object sender, RoutedEventArgs e)
{
MyText = @"Simple text with http://mywebsite.com link";
}

I can see such a result:

SampleLink

Hyperlink in TextBlock is is not clickable

The text is not clickable.

That is because your Hyperlink text is not even shown. You see the last Run that you have added to the Inlines collection, not the hyperlink itself.

You add the same Run named finishedUrl to your Hyperlink and its containing TextBlock, but you have to create a separate Run instance for the Hyperlink.

var finishedText = new Run("Some text");
var finishedUrl = "http://somewhere";
var finishedUrlRun = new Run(finishedUrl);

var hyperlink = new Hyperlink(finishedUrlRun) { NavigateUri = new Uri("http://somewhere") };

hyperlink.RequestNavigate += Hyperlink_RequestNavigate;
FinishedTextBlock.Inlines.Clear();
FinishedTextBlock.Inlines.Add(finishedText);
FinishedTextBlock.Inlines.Add(hyperlink);
FinishedTextBlock.Inlines.Add(Environment.NewLine);

var finishedUrlRun1 = new Run(finishedUrl);
FinishedTextBlock.Inlines.Add(finishedUrlRun1);

Even better, just do not add the last Run, as it is redundant, and replace the NewLine with a LineBreak to get the same layout as in your image but with a link.

FinishedTextBlock.Inlines.Clear();
FinishedTextBlock.Inlines.Add(finishedText);
FinishedTextBlock.Inlines.Add(new LineBreak());
FinishedTextBlock.Inlines.Add(hyperlink);

How to add hyperlink along with text in Textbox

I'd suggest solution utilising single RichTextBox:

    <RichTextBox IsReadOnly="True" IsDocumentEnabled="True" >
<FlowDocument>
<Paragraph>
Please enter your details for login: questions follow the link
<Hyperlink NavigateUri="https:" RequestNavigate="Hyperlink_RequestNavigate">Reset Password</Hyperlink>
</Paragraph>
</FlowDocument>
</RichTextBox>

programmatically make textblock with hyperlink in between text

Here's the code to add a TextBlock with a clickable link in the middle :

Run run1 = new Run("click ");
Run run2 = new Run(" Please");
Run run3 = new Run("here.");

Hyperlink hyperlink = new Hyperlink(run3)
{
NavigateUri = new Uri("http://stackoverflow.com")
};
hyperlink.RequestNavigate += new System.Windows.Navigation.RequestNavigateEventHandler(hyperlink_RequestNavigate); //to be implemented
textBlock1.Inlines.Clear();
textBlock1.Inlines.Add(run1);
textBlock1.Inlines.Add(hyperlink);
textBlock1.Inlines.Add(run2);

C# Hyperlink in TextBlock: nothing happens when I click on it

You need to handle the hyperlink's RequestNavigate event. Here's a quick way of doing it:

link.RequestNavigate += (sender, e) =>
{
System.Diagnostics.Process.Start(e.Uri.ToString());
};

how to make Textbox text as Hyperlink in WPF

First, I'm not sure why you'd want to do this... if the text becomes a clickable hyperlink the instant it's a valid URI, how would you continue to edit it?

The Hyperlink control doesn't do anything special for you and it can't be hosted in a TextBox. Instead, use a regular TextBox, check the text for a valid URI every time it's updated, and apply a style to make the text look like a clickable link.

<TextBox TextChanged="TextBox_TextChanged" MouseDoubleClick="TextBox_MouseDoubleClick">
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<DataTrigger Binding="{Binding HasValidURI}" Value="True">
<Setter Property="TextDecorations" Value="Underline"/>
<Setter Property="Foreground" Value="#FF2A6DCD"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>

Every time the text is changed, TextBox_TextChanged is called. This checks whether the text is a valid URI using Uri.TryCreate(). If so, a property HasValidURI is set to true. A DataTrigger in the TextBox's style picks this up and makes the text underlined and blue.

Making the hyperlink immediately clickable would cause you not to be able to position the cursor, so I watch for a double-click instead. When one is received, convert the text to a URI again and kick off a Process with that URI.

public partial class MainWindow : Window, INotifyPropertyChanged
{
private bool _hasValidURI;

public bool HasValidURI
{
get { return _hasValidURI; }
set { _hasValidURI = value; OnPropertyChanged( "HasValidURI" ); }
}

public event PropertyChangedEventHandler PropertyChanged;

public void OnPropertyChanged( string name )
{
var handler = PropertyChanged;
if( handler != null ) handler( this, new PropertyChangedEventArgs( name ) );
}

public MainWindow()
{
InitializeComponent();
this.DataContext = this;
}

private void TextBox_TextChanged( object sender, TextChangedEventArgs e )
{
Uri uri;
HasValidURI = Uri.TryCreate( (sender as TextBox).Text, UriKind.Absolute, out uri );
}

private void TextBox_MouseDoubleClick( object sender, MouseButtonEventArgs e )
{
Uri uri;
if( Uri.TryCreate( (sender as TextBox).Text, UriKind.Absolute, out uri ) )
{
Process.Start( new ProcessStartInfo( uri.AbsoluteUri ) );
}
}
}

Example using Hyperlink in WPF

If you want your application to open the link in a web browser you need to add a HyperLink with the RequestNavigate event set to a function that programmatically opens a web-browser with the address as a parameter.

<TextBlock>           
<Hyperlink NavigateUri="http://www.google.com" RequestNavigate="Hyperlink_RequestNavigate">
Click here
</Hyperlink>
</TextBlock>

In the code-behind you would need to add something similar to this to handle the RequestNavigate event:

private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e)
{
// for .NET Core you need to add UseShellExecute = true
// see https://docs.microsoft.com/dotnet/api/system.diagnostics.processstartinfo.useshellexecute#property-value
Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri));
e.Handled = true;
}

In addition you will also need the following imports:

using System.Diagnostics;
using System.Windows.Navigation;

It will look like this in your application:

oO



Related Topics



Leave a reply



Submit