Contoh menggunakan Hyperlink di WPF

160

Saya telah melihat beberapa saran, agar Anda dapat menambahkan hyperlink ke aplikasi WPF melalui Hyperlinkkontrol.

Inilah cara saya mencoba menggunakannya dalam kode saya:

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

Saya mendapatkan kesalahan berikut:

Properti 'Teks' tidak mendukung nilai tipe 'Hyperlink'.

Apa yang saya lakukan salah?

Arsen Zahray
sumber

Jawaban:

331

Jika Anda ingin aplikasi Anda membuka tautan di peramban web, Anda perlu menambahkan HyperLink dengan acara RequestNavigate diatur ke fungsi yang secara terprogram membuka peramban web dengan alamat sebagai parameter.

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

Dalam kode-belakang Anda perlu menambahkan sesuatu yang mirip dengan ini untuk menangani acara RequestNavigate.

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

Selain itu Anda juga akan memerlukan impor berikut.

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

Akan terlihat seperti ini di aplikasi Anda.

oo

eandersson
sumber
6
Catatan: RequestNavigateEventArgsada di System.Windows.Navigationnamespace.
Ben
2
Terima kasih, tetapi apakah ada cara untuk menentukan teks tautan ("Klik di sini" dalam hal ini) melalui pengikatan?
Agent007
6
Cukup letakkan Textblock di dalam Hyperlink lagi dan Bind the Textproperty
KroaX
2
Catatan # 2: Processdan ProcessStartInfokeduanya di System.Diagnosticsnamespace.
user2023861
3
Komentar penting : Anda harus memiliki NavigateUri yang tidak kosong atau event RequestNavigate tidak pernah dipanggil
MuiBienCarlota
60

Selain respons Fuji, kita dapat membuat pawang dapat digunakan kembali mengubahnya menjadi properti terlampir:

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

Dan gunakan seperti ini:

<TextBlock>
<Hyperlink NavigateUri="http://stackoverflow.com" custom::HyperlinkExtensions.IsExternal="true">
       Click here
    </Hyperlink>
 </TextBlock>
Arthur Nunes
sumber
Solusi elegan. Terima kasih
Jeson Martajaya
30

Hyperlinkadalah tidak kontrol, itu adalah konten aliran elemen, Anda hanya dapat menggunakannya dalam kontrol yang konten dukungan aliran, seperti TextBlock. TextBoxeshanya memiliki teks biasa.

HB
sumber
26

Jika Anda ingin melokalisasi string nanti, maka jawaban itu tidak cukup, saya akan menyarankan sesuatu seperti:

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

IMHO cara paling sederhana adalah dengan menggunakan kontrol baru yang diwarisi dari 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
sumber
16

Perhatikan juga bahwa Hyperlinktidak harus digunakan untuk navigasi. Anda dapat menghubungkannya ke perintah.

Sebagai contoh:

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

Saya menggunakan jawaban dalam pertanyaan ini dan saya punya masalah dengan itu.

Ini mengembalikan pengecualian: {"The system cannot find the file specified."}

Setelah sedikit penyelidikan. Ternyata bahwa jika aplikasi WPF Anda .CORE Anda perlu membuat UseShellExecuteuntuktrue .

Ini disebutkan dalam dokumen Microsoft :

true jika shell harus digunakan saat memulai proses; false jika proses harus dibuat langsung dari file yang dapat dieksekusi. Defaultnya benar pada aplikasi .NET Framework dan false pada aplikasi .NET Core.

Jadi untuk membuatnya bekerja, Anda perlu menambahkan UseShellExecuteke true:

Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri){ UseShellExecute = true });
maytham-ɯɐɥʇʎɐɯ
sumber
Saya memiliki masalah yang sama dan datang ke sini untuk melihat cara memperbaikinya, tetapi masih ada UseShelExecute = truealasan mengapa?
High Plains Grifter
@HighPlainsGrifter jadi hanya untuk memahami Anda membuat UseShelExecute = benar tetapi masih memiliki masalah yang sama? jika itu masalahnya, coba jalankan studio visual Anda dalam mode admin (jalankan sebagai administrator) Saya pikir proses ini perlu mengakses sumber daya yang memerlukan hak istimewa admin. Dan hal yang benar ini hanya berlaku untuk proyek .core. beri tahu saya jika itu membantu sehingga saya dapat memperbarui jawaban saya.
maytham-ɯɐɥʇʎɐɯ
ya, saya menjalankan sebagai pengguna admin saya dan memiliki Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri) { UseShellExecute = true });dan mendapatkan kesalahan "System.ComponentModel.Win32Exception: 'Sistem tidak dapat menemukan file yang ditentukan'" ketika saya mencoba mengikuti hyperlink
High Plains Grifter
@HighPlainsGrifter tidak yakin lagi apa itu bisa, jika Anda memiliki kode sumber saya akan menghabiskan waktu untuk debugging tetapi tidak menjanjikan apa pun. :)
maytham-ɯɐɥʇʎɐɯ
Sayangnya, kode yang tidak dapat dibagikan dengan sedih - Saya hanya harus tidak menggunakan hyperlink untuk saat ini daripada menahan proyek. Bagaimanapun, terima kasih.
High Plains Grifter
4

Saya menyukai gagasan Arthur tentang penangan yang dapat digunakan kembali, tetapi saya pikir ada cara yang lebih sederhana untuk melakukannya:

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

Jelas ada risiko keamanan dengan memulai segala jenis proses, jadi berhati-hatilah.

Hibah
sumber
1

Semoga ini bisa membantu seseorang juga.

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

Salah satu cara paling indah menurut saya (karena sekarang sudah umum tersedia) adalah menggunakan perilaku.

Itu membutuhkan:

  • ketergantungan nuget: Microsoft.Xaml.Behaviors.Wpf
  • jika Anda sudah memiliki perilaku bawaan, Anda mungkin harus mengikuti panduan ini di blog Microsoft.

kode xaml:

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

DAN

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

kode perilaku:

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
sumber