Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Example using Hyperlink in WPF

I've seen several suggestions, that you can add hyperlink to WPF application through Hyperlink control.

Here's how I'm trying to use it in my code:

<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
        mc:Ignorable="d" 
        x:Class="BookmarkWizV2.InfoPanels.Windows.UrlProperties"
        Title="UrlProperties" Height="754" Width="576">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition Height="40"/>
        </Grid.RowDefinitions>
        <Grid>
            <ScrollViewer ScrollViewer.VerticalScrollBarVisibility="Auto" Grid.RowSpan="2">
                <StackPanel >
                    <DockPanel LastChildFill="True" Margin="0,5">
                        <TextBlock Text="Url:" Margin="5" 
                            DockPanel.Dock="Left" VerticalAlignment="Center"/>
                        <TextBox Width="Auto">
                            <Hyperlink NavigateUri="http://www.google.co.in">
                                    Click here
                            </Hyperlink>   
                        </TextBox>                      
                    </DockPanel >
                </StackPanel>
            </ScrollViewer>        
        </Grid>
        <StackPanel HorizontalAlignment="Right" Orientation="Horizontal" Margin="0,7,2,7" Grid.Row="1" >
            <Button Margin="0,0,10,0">
                <TextBlock Text="Accept" Margin="15,3" />
            </Button>
            <Button Margin="0,0,10,0">
                <TextBlock Text="Cancel" Margin="15,3" />
            </Button>
        </StackPanel>
    </Grid>
</Window>

I'm getting following error:

Property 'Text' does not support values of type 'Hyperlink'.

What am I doing wrong?

like image 626
Arsen Zahray Avatar asked Apr 20 '12 00:04

Arsen Zahray


People also ask

How do I create a link in WPF?

The Hyperlink element is an inline-level content element that is used to add a hyperlink to a FlowDocument contents. You can add hyperlink support to any Inline element. The Hyperlink element is an inline-level content element that is used to add a hyperlink to a FlowDocument contents.

How do you add a hyperlink in XAML?

In XAML, the creation of content elements is implicit, so you can add the link text directly to the Hyperlink, and the Hyperlink directly to the TextBlock element. The Span element with the xml:space="preserve" attribute is used to preserve white space around the hyperlink.

How do I add a link button in WPF?

Hello, Link button in ASP.NET at runtime works like a hyperlink, but you can write certain code with the use of a link button by generating its click event, in short the link button control looks like a hyperlink control but works like a button... Here is some code that might help you out.


10 Answers

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

like image 171
eandersson Avatar answered Oct 08 '22 17:10

eandersson


In addition to Fuji's response, we can make the handler reusable turning it into an attached property:

public static class HyperlinkExtensions
{
    public static bool GetIsExternal(DependencyObject obj)
    {
        return (bool)obj.GetValue(IsExternalProperty);
    }

    public static void SetIsExternal(DependencyObject obj, bool value)
    {
        obj.SetValue(IsExternalProperty, value);
    }
    public static readonly DependencyProperty IsExternalProperty =
        DependencyProperty.RegisterAttached("IsExternal", typeof(bool), typeof(HyperlinkExtensions), new UIPropertyMetadata(false, OnIsExternalChanged));

    private static void OnIsExternalChanged(object sender, DependencyPropertyChangedEventArgs args)
    {
        var hyperlink = sender as Hyperlink;

        if ((bool)args.NewValue)
            hyperlink.RequestNavigate += Hyperlink_RequestNavigate;
        else
            hyperlink.RequestNavigate -= Hyperlink_RequestNavigate;
    }

    private static void Hyperlink_RequestNavigate(object sender, System.Windows.Navigation.RequestNavigateEventArgs e)
    {
        Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri));
        e.Handled = true;
    }
}

And use it like this:

<TextBlock>
    <Hyperlink NavigateUri="https://stackoverflow.com"
               custom:HyperlinkExtensions.IsExternal="true">
        Click here
    </Hyperlink>
</TextBlock>
like image 45
Arthur Nunes Avatar answered Oct 08 '22 17:10

Arthur Nunes


If you want to localize string later, then those answers aren't enough, I would suggest something like:

<TextBlock>
    <Hyperlink NavigateUri="http://labsii.com/">
       <Hyperlink.Inlines>
            <Run Text="Click here"/>
       </Hyperlink.Inlines>
   </Hyperlink>
</TextBlock>
like image 44
Ivan Ičin Avatar answered Oct 08 '22 16:10

Ivan Ičin


Hyperlink is not a control, it is a flow content element, you can only use it in controls which support flow content, like a TextBlock. TextBoxes only have plain text.

like image 33
H.B. Avatar answered Oct 08 '22 17:10

H.B.


Note too that Hyperlink does not have to be used for navigation. You can connect it to a command.

For example:

<TextBlock>
  <Hyperlink Command="{Binding ClearCommand}">Clear</Hyperlink>
</TextBlock>
like image 32
Drew Noakes Avatar answered Oct 08 '22 17:10

Drew Noakes


IMHO the simplest way is to use new control inherited from Hyperlink:

/// <summary>
/// Opens <see cref="Hyperlink.NavigateUri"/> in a default system browser
/// </summary>
public class ExternalBrowserHyperlink : Hyperlink
{
    public ExternalBrowserHyperlink()
    {
        RequestNavigate += OnRequestNavigate;
    }

    private void OnRequestNavigate(object sender, RequestNavigateEventArgs e)
    {
        Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri));
        e.Handled = true;
    }
}
like image 42
Lu55 Avatar answered Oct 08 '22 17:10

Lu55


I used the answer in this question and I got an issue with it.

It return exception: {"The system cannot find the file specified."}

After a bit of investigation. It turns out that if your WPF application is CORE, you need to change UseShellExecute to true.

This is mentioned in Microsoft docs:

true if the shell should be used when starting the process; false if the process should be created directly from the executable file. The default is true on .NET Framework apps and false on .NET Core apps.

So to make this work you need to added UseShellExecute and set it to true:

Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri){ UseShellExecute = true });
like image 34
Maytham Avatar answered Oct 08 '22 17:10

Maytham


I liked Arthur's idea of a reusable handler, but I think there's a simpler way to do it:

private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e)
{
    if (sender.GetType() != typeof (Hyperlink))
        return;
    string link = ((Hyperlink) sender).NavigateUri.ToString();
    Process.Start(link);
}

Obviously there could be security risks with starting any kind of process, so be carefull.

like image 32
Grant Avatar answered Oct 08 '22 16:10

Grant


One of the most beautiful ways in my opinion (since it is now commonly available) is using behaviours.

It requires:

  • nuget dependency: Microsoft.Xaml.Behaviors.Wpf
  • if you already have behaviours built in you might have to follow this guide on Microsofts blog.

xaml code:

xmlns:Interactions="http://schemas.microsoft.com/xaml/behaviors"

AND

<Hyperlink NavigateUri="{Binding Path=Link}">
    <Interactions:Interaction.Behaviors>
        <behaviours:HyperlinkOpenBehaviour ConfirmNavigation="True"/>
    </Interactions:Interaction.Behaviors>
    <Hyperlink.Inlines>
        <Run Text="{Binding Path=Link}"/>
    </Hyperlink.Inlines>
</Hyperlink>

behaviour code:

using System.Windows;
using System.Windows.Documents;
using System.Windows.Navigation;
using Microsoft.Xaml.Behaviors;

namespace YourNameSpace
{
    public class HyperlinkOpenBehaviour : Behavior<Hyperlink>
    {
        public static readonly DependencyProperty ConfirmNavigationProperty = DependencyProperty.Register(
            nameof(ConfirmNavigation), typeof(bool), typeof(HyperlinkOpenBehaviour), new PropertyMetadata(default(bool)));

        public bool ConfirmNavigation
        {
            get { return (bool) GetValue(ConfirmNavigationProperty); }
            set { SetValue(ConfirmNavigationProperty, value); }
        }

        /// <inheritdoc />
        protected override void OnAttached()
        {
            this.AssociatedObject.RequestNavigate += NavigationRequested;
            this.AssociatedObject.Unloaded += AssociatedObjectOnUnloaded;
            base.OnAttached();
        }

        private void AssociatedObjectOnUnloaded(object sender, RoutedEventArgs e)
        {
            this.AssociatedObject.Unloaded -= AssociatedObjectOnUnloaded;
            this.AssociatedObject.RequestNavigate -= NavigationRequested;
        }

        private void NavigationRequested(object sender, RequestNavigateEventArgs e)
        {
            if (!ConfirmNavigation || MessageBox.Show("Are you sure?", "Question", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
            {
                OpenUrl();
            }

            e.Handled = true;
        }

        private void OpenUrl()
        {
//          Process.Start(new ProcessStartInfo(AssociatedObject.NavigateUri.AbsoluteUri));
            MessageBox.Show($"Opening {AssociatedObject.NavigateUri}");
        }

        /// <inheritdoc />
        protected override void OnDetaching()
        {
            this.AssociatedObject.RequestNavigate -= NavigationRequested;
            base.OnDetaching();
        }
    }
}
like image 32
Dbl Avatar answered Oct 08 '22 18:10

Dbl


Hope this help someone as well.

using System.Diagnostics;
using System.Windows.Documents;

namespace Helpers.Controls
{
    public class HyperlinkEx : Hyperlink
    {
        protected override void OnClick()
        {
            base.OnClick();

            Process p = new Process()
            {
                StartInfo = new ProcessStartInfo()
                {
                    FileName = this.NavigateUri.AbsoluteUri
                }
            };
            p.Start();
        }
    }
}
like image 32
jaysonragasa Avatar answered Oct 08 '22 18:10

jaysonragasa