Ví dụ sử dụng Hyperlink trong WPF


160

Tôi đã thấy một số gợi ý, rằng bạn có thể thêm siêu liên kết vào ứng dụng WPF thông qua Hyperlinkkiểm soát.

Đây là cách tôi đang cố gắng sử dụng nó trong mã của mình:

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

Tôi đang gặp lỗi sau:

Thuộc tính 'Văn bản' không hỗ trợ các giá trị loại 'Siêu liên kết'.

Tôi đang làm gì sai?

Câu trả lời:


331

Nếu bạn muốn ứng dụng của mình mở liên kết trong trình duyệt web, bạn cần thêm HyperLink với sự kiện RequestNavigate được đặt thành chức năng mở trình duyệt web với địa chỉ làm tham số.

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

Trong mã phía sau, bạn sẽ cần thêm một cái gì đó tương tự như thế này để xử lý sự kiện RequestNavigate.

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

Ngoài ra, bạn cũng sẽ cần nhập khẩu sau đây.

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

Nó sẽ trông như thế này trong ứng dụng của bạn.

oO


6
Lưu ý: RequestNavigateEventArgslà trong System.Windows.Navigationkhông gian tên.
Ben

2
Cảm ơn, nhưng có cách nào để chỉ định văn bản liên kết ("Bấm vào đây" trong trường hợp này) thông qua ràng buộc không?
Đặc vụ007

6
Chỉ cần đặt lại Textblock bên trong Hyperlink và ràng buộc Textproperty
KroaX

2
Lưu ý # 2: ProcessProcessStartInfocả hai đều trong System.Diagnosticskhông gian tên.
2023861

3
Nhận xét quan trọng : bạn phải có một NavigateUri không trống hoặc sự kiện RequestNavigate không bao giờ được gọi
MuiBienCarlota

60

Ngoài phản hồi của Fuji, chúng tôi có thể khiến trình xử lý có thể tái sử dụng biến nó thành một tài sản đính kèm:

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

Và sử dụng nó như thế này:

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

Giải pháp thanh lịch. Cảm ơn bạn
Jeson Martajaya

30

Hyperlinkkhông một điều khiển, nó là một nội dung dòng chảy yếu tố, bạn chỉ có thể sử dụng nó trong điều khiển mà nội dung dòng hỗ trợ, giống như một TextBlock. TextBoxeschỉ có văn bản đơn giản.


26

Nếu bạn muốn bản địa hóa chuỗi sau, thì những câu trả lời đó không đủ, tôi sẽ đề xuất một cái gì đó như:

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

21

IMHO cách đơn giản nhất là sử dụng điều khiển mới được kế thừa từ 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

Lưu ý rằng Hyperlinkkhông phải sử dụng để điều hướng. Bạn có thể kết nối nó với một lệnh.

Ví dụ:

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

16

Tôi đã sử dụng câu trả lời trong câu hỏi này và tôi gặp vấn đề với nó.

Nó trả lại ngoại lệ: {"The system cannot find the file specified."}

Sau một chút điều tra. Nó chỉ ra rằng nếu ứng dụng WPF của bạn là .CORE bạn cần phải thực hiện UseShellExecuteđể true.

Điều này được đề cập trong tài liệu của Microsoft :

đúng nếu vỏ nên được sử dụng khi bắt đầu quá trình; sai nếu quá trình nên được tạo trực tiếp từ tập tin thực thi. Mặc định là đúng trên các ứng dụng .NET Framework và sai trên các ứng dụng .NET Core.

Vì vậy, để làm cho công việc này, bạn cần thêm UseShellExecutevào true:

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

Tôi đã có vấn đề tương tự và đến đây để xem cách khắc phục, nhưng nó vẫn tồn tại với UseShelExecute = truebất kỳ ý tưởng nào tại sao?
Cao nguyên Grifter

@HighPlainsGrifter để hiểu bạn đã sử dụng UseShelExecute = true nhưng vẫn có cùng một vấn đề? nếu đó là trường hợp hãy thử chạy studio hình ảnh của bạn ở chế độ quản trị viên (chạy với tư cách quản trị viên) Tôi nghĩ rằng quy trình này cần truy cập vào các tài nguyên yêu cầu đặc quyền của quản trị viên. Và điều này đúng chỉ có giá trị cho các dự án .core. cho tôi biết nếu điều đó có ích để tôi có thể cập nhật câu trả lời của mình.
maytham-ɯɐɥʇʎɐɯ

vâng, tôi đang chạy với tư cách là người dùng quản trị viên của mình và gặp phải Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri) { UseShellExecute = true });lỗi "System.ComponentModel.Win32Exception: 'Hệ thống không thể tìm thấy tệp được chỉ định'" khi tôi cố gắng theo siêu liên kết
High Plains Grifter

@HighPlainsGrifter không chắc chắn nó có thể là gì nữa, nếu bạn có mã nguồn, tôi sẵn sàng dành thời gian để gỡ lỗi nhưng không hứa hẹn bất cứ điều gì. :)
maytham-ɯɐɥʇʎɐɯ

Thật không may là mã có thể chia sẻ đáng buồn - tôi đã không phải sử dụng một siêu liên kết bây giờ thay vì giữ dự án lên. Dẫu sao cũng xin cảm ơn.
Cao nguyên Grifter

4

Tôi thích ý tưởng của Arthur về một trình xử lý có thể tái sử dụng, nhưng tôi nghĩ có một cách đơn giản hơn để làm điều đó:

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

Rõ ràng có thể có những rủi ro bảo mật khi bắt đầu bất kỳ loại quy trình nào, vì vậy hãy cẩn thận.


1

Hy vọng điều này sẽ giúp ai đó là tốt.

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

Theo tôi, một trong những cách hay nhất (vì nó phổ biến hiện nay) là sử dụng các hành vi.

Nó yêu cầu:

  • phụ thuộc nuget: Microsoft.Xaml.Behaviors.Wpf
  • nếu bạn đã có các hành vi được xây dựng, bạn có thể phải làm theo hướng dẫn này trên blog của microsofts.

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

mã hành vi:

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();
        }
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.