ตัวอย่างการใช้ไฮเปอร์ลิงก์ใน WPF


160

ฉันเห็นคำแนะนำหลายประการที่คุณสามารถเพิ่มไฮเปอร์ลิงก์ไปยังแอปพลิเคชัน WPF ผ่านHyperlinkการควบคุม

นี่คือวิธีที่ฉันพยายามใช้ในรหัสของฉัน:

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

ฉันได้รับข้อผิดพลาดดังต่อไปนี้:

คุณสมบัติ 'ข้อความ' ไม่รองรับค่าประเภท 'ไฮเปอร์ลิงก์'

ผมทำอะไรผิดหรือเปล่า?

คำตอบ:


331

หากคุณต้องการให้แอปพลิเคชันของคุณเปิดลิงก์ในเว็บเบราว์เซอร์คุณต้องเพิ่มHyperLinkด้วยชุดเหตุการณ์RequestNavigateเป็นฟังก์ชั่นโดยทางโปรแกรมเปิดเว็บเบราว์เซอร์ที่มีที่อยู่เป็นพารามิเตอร์

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

ใน code-behind คุณจะต้องเพิ่มสิ่งที่คล้ายกับสิ่งนี้เพื่อจัดการกับ RequestNavigate เหตุการณ์

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

นอกจากนี้คุณยังจะต้องนำเข้าต่อไปนี้

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

มันจะมีลักษณะเช่นนี้ในใบสมัครของคุณ

oO


6
หมายเหตุ: RequestNavigateEventArgsอยู่ในSystem.Windows.Navigationเนมสเปซ
Ben

2
ขอขอบคุณ แต่มีวิธีระบุลิงก์ข้อความ ("คลิกที่นี่" ในกรณีนี้) ผ่านการเชื่อมโยงหรือไม่
Agent007

6
เพียงใส่เท็กซ์บล็อคเข้าไปในไฮเปอร์ลิงก์อีกครั้งแล้วผูกเท็กซ์เจอร์
KroaX

2
หมายเหตุ # 2: ProcessและProcessStartInfoทั้งคู่อยู่ในSystem.Diagnosticsเนมสเปซ
user2023861

3
หมายเหตุสำคัญ : คุณต้องมี NavigateUri ที่ว่างเปล่าหรือไม่มีการร้องขอ RequestNavigate ไม่มีเหตุการณ์
MuiBienCarlota

60

นอกเหนือจากการตอบสนองของฟูจิเราสามารถทำให้ตัวจัดการสามารถนำกลับมาใช้ใหม่ให้กลายเป็นทรัพย์สินที่แนบมาได้:

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="http://stackoverflow.com" custom::HyperlinkExtensions.IsExternal="true">
       Click here
    </Hyperlink>
 </TextBlock>

ทางออกที่สง่างาม ขอบคุณ
Jeson Martajaya

30

Hyperlinkจะไม่ควบคุมมันเป็นเนื้อหาการไหลของTextBlockองค์ประกอบที่คุณสามารถใช้ในการควบคุมซึ่งเนื้อหาการสนับสนุนการไหลเช่น TextBoxesมีข้อความล้วน


26

หากคุณต้องการ จำกัด วงสตริงในภายหลังคำตอบเหล่านั้นไม่เพียงพอฉันจะแนะนำสิ่งต่อไปนี้:

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

21

IMHO วิธีที่ง่ายที่สุดคือการใช้การควบคุมใหม่ที่สืบทอดมาจาก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;
    }
}

16

หมายเหตุด้วยเช่นกันที่Hyperlinkไม่จำเป็นต้องใช้สำหรับการนำทาง คุณสามารถเชื่อมต่อกับคำสั่ง

ตัวอย่างเช่น:

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

16

ฉันใช้คำตอบในคำถามนี้และฉันมีปัญหากับมัน

ส่งคืนข้อยกเว้น: {"The system cannot find the file specified."}

หลังจากการตรวจสอบเล็กน้อย ปรากฎว่าถ้าโปรแกรมประยุกต์ WPF คุณคือ .CORE ที่คุณต้องทำเพื่อUseShellExecutetrue

สิ่งนี้ถูกกล่าวถึงในเอกสารของ Microsoft :

true ถ้าเชลล์ควรใช้เมื่อเริ่มต้นกระบวนการ false ถ้ากระบวนการควรถูกสร้างขึ้นโดยตรงจากไฟล์เรียกทำงาน ค่าเริ่มต้นเป็นจริงในแอป. NET Framework และเท็จในแอป. NET Core

ดังนั้นเพื่อให้งานนี้คุณต้องเพิ่มUseShellExecuteไปที่true:

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

ฉันมีปัญหาเดียวกันนี้และมาที่นี่เพื่อดูวิธีแก้ไข แต่ก็ยังคงมีUseShelExecute = trueความคิดอยู่ว่าทำไม
ที่ราบสูง Grifter

@ HighPlainsGrifter เพื่อให้เข้าใจว่าคุณใช้ UseShelExecute = true แต่ยังมีปัญหาเดิมอยู่หรือไม่ หากเป็นกรณีนี้ให้ลองเรียกใช้ visual Studio ของคุณในโหมดผู้ดูแลระบบ (เรียกใช้ในฐานะผู้ดูแลระบบ) ฉันคิดว่ากระบวนการนี้จำเป็นต้องเข้าถึงทรัพยากรที่ต้องใช้สิทธิ์ผู้ดูแลระบบ และสิ่งจริงนี้ใช้ได้กับโครงการ. core เท่านั้น แจ้งให้เราทราบหากช่วยได้ฉันสามารถอัปเดตคำตอบของฉันได้
maytham-ɯɐɥʇʎɐɯ

ใช่ฉันกำลังใช้งานเป็นผู้ใช้ที่เป็นผู้ดูแลระบบและได้Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri) { UseShellExecute = true });รับข้อผิดพลาด "System.ComponentModel.Win32Exception: 'ระบบไม่พบไฟล์ที่ระบุ'" เมื่อฉันพยายามติดตามไฮเปอร์ลิงค์
High Plains Grifter

@ HighPlainsGri หลังจากไม่แน่ใจว่ามันจะเป็นอย่างไรถ้าคุณมีซอร์สโค้ดฉันก็ยินดีที่จะใช้เวลาในการดีบั๊กมัน แต่ไม่เคยสัญญาอะไรเลย :)
maytham-ɯɐɥʇʎɐɯ

รหัสที่แชร์ไม่ได้น่าเศร้าจริงๆ - ฉันเพิ่งจะต้องไม่ใช้ไฮเปอร์ลิงก์ตอนนี้แทนที่จะถือโครงการไว้ ขอบคุณอยู่ดี
ที่ราบสูง Grifter

4

ฉันชอบความคิดของ Arthur ในการใช้ตัวจัดการที่สามารถนำกลับมาใช้ใหม่ได้ แต่ฉันคิดว่าวิธีที่ง่ายกว่าคือ:

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

เห็นได้ชัดว่าอาจมีความเสี่ยงด้านความปลอดภัยเมื่อเริ่มต้นกระบวนการใด ๆ ดังนั้นจงระมัดระวัง


1

หวังว่าสิ่งนี้จะช่วยให้ใครบางคนเช่นกัน

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

0

หนึ่งในวิธีที่สวยที่สุดในความคิดของฉัน (เพราะตอนนี้ใช้ได้ทั่วไป) คือการใช้พฤติกรรม

มันต้องการ:

  • การพึ่งพา nuget: Microsoft.Xaml.Behaviors.Wpf
  • หากคุณมีพฤติกรรมในตัวอยู่แล้วคุณอาจต้องปฏิบัติตามคำแนะนำนี้ในบล็อกของ Microsoft

รหัส 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();
        }
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.