WPF - 使超链接可点击 [英] WPF - Making hyperlinks clickable

查看:47
本文介绍了WPF - 使超链接可点击的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在列表中显示一些文本.其中一些文本片段包含超链接.我想让链接在文本中点击.我可以想象这个问题的解决方案,但它们看起来确实不好看.

I've got a bit of text that I'm trying to display in a list. Some of those pieces of a text contain a hyperlink. I'd like to make the links clickable within the text. I can imagine solutions to this problem, but they sure don't seem pretty.

例如,我可以撕开字符串,将其拆分为超链接和非超链接.然后我可以动态构建一个 Textblock,适当地添加纯文本元素和超链接对象.

For instance, I could tear apart the string, splitting it into hyperlinks and non-hyperlinks. Then I could dynamically build a Textblock, adding plain text elements and hyperlink objects as appropriate.

我希望有更好的,最好是声明性的.

I'm hoping there's a better, preferably something declarative.

示例:嘿,看看这个链接:http://mylink.com 真的很酷.">

Example: "Hey, check out this link: http://mylink.com It's really cool."

推荐答案

您需要能够解析 TextBlock 的文本并在运行时创建所有内联对象的东西.为此,您可以创建自己的自定义控件,派生自 TextBlock 或附加属性.

You need something that will parse the Text of the TextBlock and create the all the inline objects at runtime. For this you can either create your own custom control derived from TextBlock or an attached property.

对于解析,您可以使用正则表达式搜索文本中的 URL.我从 一个好的 url 正则表达式? 借用了一个正则表达式,但是网络上还有其他可用的,因此您可以选择最适合您的那个.

For the parsing, you can search for URLs in the text with a regular expression. I borrowed a regular expression from A good url regular expression? but there are others available on the web, so you can choose the one which works best for you.

在下面的示例中,我使用了附加属性.要使用它,请修改您的 TextBlock 以使用 NavigateService.Text 而不是 Text 属性:

In the sample below, I used an attached property. To use it, modify your TextBlock to use NavigateService.Text instead of Text property:

<Window x:Class="DynamicNavigation.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:DynamicNavigation"
    Title="Window1" Height="300" Width="300">
    <StackPanel>
        <!-- Type something here to see it displayed in the TextBlock below -->
        <TextBox x:Name="url"/>

        <!-- Dynamically updates to display the text typed in the TextBox -->
        <TextBlock local:NavigationService.Text="{Binding Text, ElementName=url}" />
    </StackPanel>
</Window>

附加属性的代码如下:

using System;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;

namespace DynamicNavigation
{
    public static class NavigationService
    {
        // Copied from http://geekswithblogs.net/casualjim/archive/2005/12/01/61722.aspx
        private static readonly Regex RE_URL = new Regex(@"(?#Protocol)(?:(?:ht|f)tp(?:s?)://|~/|/)?(?#Username:Password)(?:w+:w+@)?(?#Subdomains)(?:(?:[-w]+.)+(?#TopLevel Domains)(?:com|org|net|gov|mil|biz|info|mobi|name|aero|jobs|museum|travel|[a-z]{2}))(?#Port)(?::[d]{1,5})?(?#Directories)(?:(?:(?:/(?:[-w~!$+|.,=]|%[a-fd]{2})+)+|/)+|?|#)?(?#Query)(?:(?:?(?:[-w~!$+|.,*:]|%[a-fd{2}])+=(?:[-w~!$+|.,*:=]|%[a-fd]{2})*)(?:&(?:[-w~!$+|.,*:]|%[a-fd{2}])+=(?:[-w~!$+|.,*:=]|%[a-fd]{2})*)*)*(?#Anchor)(?:#(?:[-w~!$+|.,*:=]|%[a-fd]{2})*)?");

        public static readonly DependencyProperty TextProperty = DependencyProperty.RegisterAttached(
            "Text",
            typeof(string),
            typeof(NavigationService),
            new PropertyMetadata(null, OnTextChanged)
        );

        public static string GetText(DependencyObject d)
        { return d.GetValue(TextProperty) as string; }

        public static void SetText(DependencyObject d, string value)
        { d.SetValue(TextProperty, value); }

        private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var text_block = d as TextBlock;
            if (text_block == null)
                return;

            text_block.Inlines.Clear();

            var new_text = (string)e.NewValue;
            if ( string.IsNullOrEmpty(new_text) )
                return;

            // Find all URLs using a regular expression
            int last_pos = 0;
            foreach (Match match in RE_URL.Matches(new_text))
            {
                // Copy raw string from the last position up to the match
                if (match.Index != last_pos)
                {
                    var raw_text = new_text.Substring(last_pos, match.Index - last_pos);
                    text_block.Inlines.Add(new Run(raw_text));
                }

                // Create a hyperlink for the match
                var link = new Hyperlink(new Run(match.Value))
                {
                    NavigateUri = new Uri(match.Value)
                };
                link.Click += OnUrlClick;

                text_block.Inlines.Add(link);

                // Update the last matched position
                last_pos = match.Index + match.Length;
            }

            // Finally, copy the remainder of the string
            if (last_pos < new_text.Length)
                text_block.Inlines.Add(new Run(new_text.Substring(last_pos)));
        }

        private static void OnUrlClick(object sender, RoutedEventArgs e)
        {
            var link = (Hyperlink)sender;
            // Do something with link.NavigateUri like:
            Process.Start(link.NavigateUri.ToString());
        }
    }
}

这篇关于WPF - 使超链接可点击的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆