在 WPF 中使用超链接的示例

我看到了一些建议,您可以通过 Hyperlink控件向 WPF 应用程序添加超链接。

下面是我在代码中使用它的方法:

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

我得到了下面的错误:

属性“ Text”不支持“ Hyperlink”类型的值。

我做错了什么?

228889 次浏览

Hyperlink没有的一个控件,它是 流量含量的一个元素,你只能在支持流量内容的控件中使用它,比如 TextBlockTextBoxes只有纯文本。

如果您希望您的应用程序打开 网页浏览器中的链接,您需要添加一个 超连结,将 请求导航事件设置为一个函数,该函数以编程方式打开一个以地址作为参数的 Web 浏览器。

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

在代码隐藏中,您需要添加一些类似的东西来处理 RequestNavigate 事件:

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

此外,你还需要以下进口产品:

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

在您的应用程序中将看起来像这样:

oO

除了富士的响应,我们还可以让处理程序可重用,把它变成一个附加属性:

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

像这样使用它:

<TextBlock>
<Hyperlink NavigateUri="https://stackoverflow.com"
custom:HyperlinkExtensions.IsExternal="true">
Click here
</Hyperlink>
</TextBlock>

我喜欢 Arthur 关于可重用处理程序的想法,但我认为有一个更简单的方法:

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

显然,启动任何类型的进程都可能存在安全风险,因此要小心。

恕我直言,最简单的方法是使用继承自 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;
}
}

如果你想稍后本地化字符串,那么这些答案是不够的,我建议你这样做:

<TextBlock>
<Hyperlink NavigateUri="https://speechcentral.net/">
<Hyperlink.Inlines>
<Run Text="Click here"/>
</Hyperlink.Inlines>
</Hyperlink>
</TextBlock>

希望这也能帮到别人。

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

还要注意的是,Hyperlink不一定要用于导航。您可以将它连接到一个命令。

例如:

<TextBlock>
<Hyperlink Command="{Binding ClearCommand}">Clear</Hyperlink>
</TextBlock>

在我看来,最美妙的方式之一(因为现在已经很普遍了)就是使用行为。

它要求:

  • Nuget 依赖项: Microsoft.Xaml.Behaviors.Wpf
  • 如果你已经有内置的行为,你可能不得不遵循这个 向导在微软博客。

Xaml 代码:

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

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

行为守则:

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

我用了这个问题的答案,我对它有意见。

它返回异常: {"The system cannot find the file specified."}

经过一番调查。事实证明,如果您的 WPF 应用程序是 CORE,则需要将 UseShellExecute更改为 true

Microsoft 医生中提到了这一点:

如果启动进程时应该使用 shell,则为 true; 如果 进程应该直接从可执行文件创建 默认在.NETFramework 应用程序中为 true,在.NETCore 应用程序中为 false。

因此,为了使这个工作,你需要添加 UseShellExecute并将其设置为 true:

Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri){ UseShellExecute = true });