Bạn cần cái gì đó sẽ phân tích các văn bản của TextBlock và tạo ra tất cả các đối tượng inline khi chạy. Đối với điều này, bạn có thể tạo điều khiển tùy chỉnh của riêng bạn bắt nguồn từ TextBlock hoặc thuộc tính đính kèm.
Để phân tích cú pháp, bạn có thể tìm kiếm URL trong văn bản bằng cụm từ thông dụng. Tôi đã mượn biểu thức chính quy từ A good url regular expression? nhưng có những người khác có sẵn trên web, do đó bạn có thể chọn biểu tượng phù hợp nhất với mình.
Trong ví dụ bên dưới, tôi đã sử dụng thuộc tính đính kèm. Để sử dụng nó, sửa đổi TextBlock bạn để sử dụng NavigateService.Text thay vì thuộc tính Text:
<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>
Mã cho tài sản gắn liền được đưa ra dưới đây:
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+:\[email protected])?(?#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-f\d]{2})+)+|/)+|\?|#)?(?#Query)(?:(?:\?(?:[-\w~!$+|.,*:]|%[a-f\d{2}])+=(?:[-\w~!$+|.,*:=]|%[a-f\d]{2})*)(?:&(?:[-\w~!$+|.,*:]|%[a-f\d{2}])+=(?:[-\w~!$+|.,*:=]|%[a-f\d]{2})*)*)*(?#Anchor)(?:#(?:[-\w~!$+|.,*:=]|%[a-f\d]{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());
}
}
}
Nguồn
2009-05-15 07:51:01
Tuyệt vời, chính xác những gì tôi đang tìm kiếm. Đã cho tôi một cách hoàn toàn mới để xem xét một số vấn đề của WPF mà tôi cũng phải đối mặt. –
Tuyệt vời! Tôi đặt phiên bản VB của câu trả lời này dưới đây. – Dabblernl
Một vấn đề nhỏ là nếu giao thức không được chỉ định (ví dụ: tôi chỉ cần nhập www.google.com), thành phần ném một ngoại lệ khi cố gắng tạo Uri (UriFormatException - "URI không hợp lệ: Định dạng của URI không thể được xác định.") –