Beispiel mit Hyperlink in WPF

160

Ich habe mehrere Vorschläge gesehen, dass Sie durch HyperlinkSteuerung einen Hyperlink zur WPF-Anwendung hinzufügen können.

So versuche ich es in meinem Code zu verwenden:

<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>

Ich erhalte folgenden Fehler:

Die Eigenschaft 'Text' unterstützt keine Werte vom Typ 'Hyperlink'.

Was mache ich falsch?

Arsen Zahray
quelle

Antworten:

331

Wenn Ihre Anwendung den Link in einem Webbrowser öffnen soll , müssen Sie einen HyperLink mit dem Ereignis RequestNavigate zu einer Funktion hinzufügen , die programmgesteuert einen Webbrowser mit der Adresse als Parameter öffnet.

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

Im Code-Behind müssten Sie etwas Ähnliches hinzufügen, um das RequestNavigate-Ereignis zu behandeln.

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

Darüber hinaus benötigen Sie auch die folgenden Importe.

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

In Ihrer Bewerbung würde es so aussehen.

oO

eandersson
quelle
6
Hinweis: RequestNavigateEventArgsbefindet sich im System.Windows.NavigationNamespace.
Ben
2
Danke, aber gibt es eine Möglichkeit, den Link-Text (in diesem Fall "Hier klicken") durch Bindung anzugeben?
Agent007
6
Fügen
Sie
2
Hinweis Nr. 2: Processund ProcessStartInfobefinden sich beide im System.DiagnosticsNamespace.
user2023861
3
Wichtiger Hinweis : Sie müssen ein nicht leeres NavigateUri oder Ereignis haben. RequestNavigate wird niemals aufgerufen
MuiBienCarlota
60

Zusätzlich zu Fujis Antwort können wir den Handler wiederverwendbar machen und ihn in eine angehängte Eigenschaft verwandeln:

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;
    }
}

Und benutze es so:

<TextBlock>
<Hyperlink NavigateUri="http://stackoverflow.com" custom::HyperlinkExtensions.IsExternal="true">
       Click here
    </Hyperlink>
 </TextBlock>
Arthur Nunes
quelle
Elegante Lösung. Vielen Dank
Jeson Martajaya
30

Hyperlinkist nicht eine Kontrolle, es ist ein Fluss Inhalt Element, können Sie es nur in Steuerelemente verwenden ein , die Unterstützung fortlaufenden Inhalt, wie TextBlock. TextBoxeshabe nur Klartext.

HB
quelle
26

Wenn Sie die Zeichenfolge später lokalisieren möchten, reichen diese Antworten nicht aus. Ich würde Folgendes vorschlagen:

<TextBlock>
    <Hyperlink NavigateUri="http://labsii.com/">
       <Hyperlink.Inlines>
            <Run Text="Click here"/>
       </Hyperlink.Inlines>
   </Hyperlink>
</TextBlock>
Ivan Ičin
quelle
21

IMHO ist der einfachste Weg, ein neues Steuerelement zu verwenden, das geerbt wurde von 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;
    }
}
Lu55
quelle
16

Beachten Sie auch, dass Hyperlinknicht für die Navigation verwendet werden muss. Sie können es mit einem Befehl verbinden.

Beispielsweise:

<TextBlock>
  <Hyperlink Command="{Binding ClearCommand}">Clear</Hyperlink>
</TextBlock>
Drew Noakes
quelle
16

Ich habe die Antwort in dieser Frage verwendet und habe Probleme damit.

Es wird eine Ausnahme zurückgegeben: {"The system cannot find the file specified."}

Nach ein bisschen Nachforschungen. Es stellt sich heraus , dass , wenn Ihre WPF - Anwendung .CORE ist Sie brauchen , um UseShellExecutezu true.

Dies wird in Microsoft- Dokumenten erwähnt :

true, wenn die Shell beim Starten des Prozesses verwendet werden soll; false, wenn der Prozess direkt aus der ausführbaren Datei erstellt werden soll. Der Standardwert ist für .NET Framework-Apps true und für .NET Core-Apps false.

So machen Sie diese Arbeit , die Sie hinzugefügt müssen , UseShellExecuteum true:

Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri){ UseShellExecute = true });
Maytham-ɯɐɥʇʎɐɯ
quelle
Ich hatte das gleiche Problem und kam hierher, um zu sehen, wie ich es beheben kann, aber es bleibt bei UseShelExecute = truejeder Idee, warum?
High Plains Grifter
@HighPlainsGrifter, nur um zu verstehen, dass Sie UseShelExecute = true gemacht haben, aber immer noch das gleiche Problem haben? Wenn dies der Fall ist, versuchen Sie, Ihr Visual Studio im Administratormodus auszuführen (als Administrator ausführen). Ich denke, dieser Prozess muss auf Ressourcen zugreifen, für die Administratorrechte erforderlich sind. Und diese wahre Sache gilt nur für .core-Projekte. Lassen Sie mich wissen, ob dies hilft, damit ich meine Antwort aktualisieren kann.
Maytham - 12.
Ja, ich werde als Administrator ausgeführt Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri) { UseShellExecute = true });und erhalte und erhalte die Fehlermeldung "System.ComponentModel.Win32Exception: 'Das System kann die angegebene Datei nicht finden'", wenn ich versuche, dem Hyperlink zu folgen
High Plains Grifter
@HighPlainsGrifter Ich bin mir nicht sicher, was es sonst sein kann. Wenn Sie Quellcode haben, möchte ich einige Zeit damit verbringen, ihn zu debuggen, verspreche aber nichts. :)
Maytham-ɯɐɥʇʎɐɯ
Leider kein wirklich gemeinsam nutzbarer Code - ich musste vorerst keinen Hyperlink verwenden, anstatt das Projekt aufzuhalten. Danke trotzdem.
High Plains Grifter
4

Ich mochte Arthurs Idee eines wiederverwendbaren Handlers, aber ich denke, es gibt einen einfacheren Weg, dies zu tun:

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

Offensichtlich kann es Sicherheitsrisiken geben, wenn ein Prozess gestartet wird. Seien Sie also vorsichtig.

Gewähren
quelle
1

Hoffe das hilft auch jemandem.

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();
        }
    }
}
jaysonragasa
quelle
0

Eine der schönsten Möglichkeiten meiner Meinung nach (da es jetzt allgemein verfügbar ist) ist die Verwendung von Verhaltensweisen.

Es benötigt:

  • Nuget-Abhängigkeit: Microsoft.Xaml.Behaviors.Wpf
  • Wenn Sie bereits Verhaltensweisen eingebaut haben, müssen Sie möglicherweise diesem Handbuch im Microsoft-Blog folgen .

XAML-Code:

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

UND

<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>

Verhaltenscode:

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();
        }
    }
}
Dbl
quelle