WPF에서 하이퍼 링크를 사용하는 예


160

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'유형의 값을 지원하지 않습니다.

내가 뭘 잘못하고 있죠?

답변:


331

당신이의 링크를 열려면 응용 프로그램하려면 웹 브라우저를 당신은 추가 할 필요가 하이퍼 링크를RequestNavigate의 프로그램 매개 변수로 주소를 웹 브라우저를 열고 함수에 이벤트 세트.

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

코드 숨김에서 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;

응용 프로그램에서 이와 같이 보입니다.

우


6
참고 : RequestNavigateEventArgsSystem.Windows.Navigation네임 스페이스.
Ben

2
고맙지 만 바인딩을 통해 링크 텍스트 (이 경우 "여기를 클릭하십시오")를 지정하는 방법이 있습니까?
Agent007

6
하이퍼 링크 안에 텍스트 블록을 다시 넣고 텍스트 속성 바인딩
KroaX

2
참고 # 2 : Process와 네임 스페이스에 ProcessStartInfo모두 System.Diagnostics있습니다.
user2023861

3
중요 사항 : 비어 있지 않은 NavigateUri가 있거나 이벤트 RequestNavigate가 호출되지 않아야 함
MuiBienCarlota

60

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

가장 간단한 방법은 다음에서 상속 된 새로운 컨트롤을 사용하는 것입니다 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 인 경우 확인 UseShellExecute해야 true합니다.

이것은 Microsoft 문서 에서 언급되었습니다 .

프로세스를 시작할 때 쉘을 사용해야하는 경우 true; 프로세스를 실행 파일에서 직접 작성해야하는 경우 false입니다. 기본값은 .NET Framework 앱에서 true이고 .NET Core 앱에서 false입니다.

따라서이 작업을 수행하려면 다음을 추가해야 UseShellExecute합니다 true.

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

나는이 같은 문제가 있었고 그것을 고치는 방법을보기 위해 여기에 왔지만 UseShelExecute = true왜 여전히 어떤 생각으로 지속 됩니까?
High Plains Grifter

@ HighPlainsGrifter 그래서 당신이 UseShelExecute = true 였지만 여전히 같은 문제가 있음을 이해하기 위해? 이 경우 관리자 모드로 Visual Studio를 실행하려고하면 (관리자 권한으로 실행)이 프로세스가 관리자 권한이 필요한 리소스에 액세스해야한다고 생각합니다. 그리고이 사실은 .core 프로젝트에만 유효합니다. 도움이되는지 알려 주면 답변을 업데이트 할 수 있습니다.
maytham-ɯɐɥʇʎɐɯ

예, 관리자로 실행 중이며 Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri) { UseShellExecute = true });하이퍼 링크를 따르려고 할 때 "System.ComponentModel.Win32Exception : '시스템이 지정된 파일을 찾을 수 없습니다'"오류가 발생합니다.
High Plains Grifter

@ HighPlainsGrifter 다른 코드가 무엇인지 잘 모르겠습니다. 소스 코드가 있으면 디버깅하는 데 시간이 많이 걸리지 만 약속하지는 않습니다. :)
maytham-ɯɐɥʇʎɐɯ '12

슬프게도 공유 가능한 코드는 아닙니다. 프로젝트를 유지하기보다는 하이퍼 링크를 사용하지 않아도되었습니다. 어쨌든 고마워.
High Plains 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

내 생각에 가장 아름다운 방법 중 하나는 (지금은 일반적으로 사용 가능하기 때문에) 행동을 사용하는 것입니다.

필요합니다 :

  • 너겟 의존성 : 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.