【问题标题】:Example using Hyperlink in WPF在 WPF 中使用超链接的示例
【发布时间】:2012-05-01 14:15:47
【问题描述】:

我看到了一些建议,您可以通过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>

我收到以下错误:

“文本”属性不支持“超链接”类型的值。

我做错了什么?

【问题讨论】:

    标签: c# wpf xaml hyperlink


    【解决方案1】:

    如果您希望您的应用程序打开web browser 中的链接,您需要添加一个HyperLink 并将RequestNavigate 事件设置为以编程方式打开具有该地址作为参数的网络浏览器的函数。

    <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://docs.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;
    

    它在您的应用程序中将如下所示:

    【讨论】:

    • 谢谢,但是有没有办法通过绑定指定链接文本(在这种情况下为“单击此处”)?
    • 只需再次在超链接中放置一个文本块并绑定文本属性
    • @Thomas - 要执行命令,只需将必要的命令绑定到超链接的 Command 属性即可。
    • 重要提示:你必须有一个非空的 NavigateUri 或事件 RequestNavigate 永远不会被调用
    • 我必须这样做: Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri) { UseShellExecute = true });否则它说它没有找到指定的文件。
    【解决方案2】:

    除了 Fuji 的响应之外,我们还可以让处理程序可重用,将其变成附加属性:

    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>
    

    【讨论】:

    • 优雅的解决方案。谢谢
    【解决方案3】:

    Hyperlink 不是控件,它是flow content 元素,您只能在支持流内容的控件中使用它,例如TextBlockTextBoxes 只有纯文本。

    【讨论】:

      【解决方案4】:

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

      <TextBlock>
          <Hyperlink NavigateUri="http://labsii.com/">
             <Hyperlink.Inlines>
                  <Run Text="Click here"/>
             </Hyperlink.Inlines>
         </Hyperlink>
      </TextBlock>
      

      【讨论】:

        【解决方案5】:

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

        【讨论】:

          【解决方案6】:

          还要注意Hyperlink 不必用于导航。您可以将其连接到命令。

          例如:

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

          【讨论】:

            【解决方案7】:

            我在这个问题中使用了答案,但遇到了问题。

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

            经过一番调查。原来如果你的WPF应用是CORE,需要把UseShellExecute改成true

            这在微软docs中提到:

            如果在启动进程时应该使用 shell,则为 true;假如果 该进程应直接从可执行文件创建。这 在 .NET Framework 应用上默认为 true,在 .NET Core 应用上默认为 false。

            所以要完成这项工作,您需要添加 UseShellExecute 并将其设置为 true

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

            【讨论】:

            • 我遇到了同样的问题,来到这里看看如何解决它,但它仍然存在 UseShelExecute = true 知道为什么吗?
            • @HighPlainsGrifter 所以只是为了理解你做了 UseShelExecute = true 但仍然有同样的问题?如果是这种情况,请尝试以管理员模式运行您的 Visual Studio(以管理员身份运行),我认为此过程需要访问需要管理员权限的资源。而这个真实的东西只对 .core 项目有效。让我知道这是否有帮助,以便我更新我的答案。
            • 是的,我以管理员用户身份运行并拥有Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri) { UseShellExecute = true }); 并在我尝试点击超链接时收到错误“System.ComponentModel.Win32Exception:'系统找不到指定的文件'”
            • @HighPlainsGrifter 不确定它可能是什么,如果你有源代码,我愿意花一些时间调试它,但不会承诺任何事情。 :)
            • 可悲的是,代码并不是真正可共享的——我现在只需要不使用超链接而不是阻止项目。无论如何,谢谢。
            【解决方案8】:

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

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

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

            【讨论】:

              【解决方案9】:

              我认为最漂亮的方法之一(因为它现在很常见)是使用行为。

              需要:

              • nuget 依赖:Microsoft.Xaml.Behaviors.Wpf
              • 如果您已经内置了行为,您可能需要关注 Microsoft 博客上的 guide

              xml代码:

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

              【讨论】:

                【解决方案10】:

                希望这对某人也有帮助。

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

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2013-05-06
                  • 2022-12-04
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-05-31
                  • 2010-10-26
                  • 2020-07-20
                  • 1970-01-01
                  相关资源
                  最近更新 更多