问候, 我在db中有一些文本,如下所示:
Lorem ipsum dolor坐下来,精神上的精神。 DUIS tellus nisl,venenatis et pharetra ac,tempor sed sapien。整数 pellentesque blandit velit,in tempus urna semper sit amet。 DUIS mollis,libero ut consectetur interdum,massa tellus posuere nisi,eu alquet elit lacus nec erat。赞美商品。 **[一个 href ='http://somesite.com']某个网站[/ a] **在尼斯的Suspendisse坐下来 Massa molestie gravida feugiat ac sem。 Phasellus ac mauris ipsum,vel auctor odio
我的问题是:如何在Hyperlink
中显示TextBlock
?我不想为此目的使用webBrowser控件。
我也不想使用此控件:http://www.codeproject.com/KB/WPF/htmltextblock.aspx也
答案 0 :(得分:89)
显示相当简单,导航是另一个问题。 XAML是这样的:
<TextBlock Name="TextBlockWithHyperlink">
Some text
<Hyperlink
NavigateUri="http://somesite.com"
RequestNavigate="Hyperlink_RequestNavigate">
some site
</Hyperlink>
some more text
</TextBlock>
启动默认浏览器以导航到超链接的事件处理程序将是:
private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e) {
System.Diagnostics.Process.Start(e.Uri.ToString());
}
编辑:要使用您从数据库获得的文本来执行此操作,您必须以某种方式解析文本。一旦知道了文本部分和超链接部分,就可以在代码中动态构建文本块内容:
TextBlockWithHyperlink.Inlines.Clear();
TextBlockWithHyperlink.Inlines.Add("Some text ");
Hyperlink hyperLink = new Hyperlink() {
NavigateUri = new Uri("http://somesite.com")
};
hyperLink.Inlines.Add("some site");
hyperLink.RequestNavigate += Hyperlink_RequestNavigate;
TextBlockWithHyperlink.Inlines.Add(hyperLink);
TextBlockWithHyperlink.Inlines.Add(" Some more text");
答案 1 :(得分:15)
在这种情况下,您可以将Regex与值转换器一起使用。
根据您的要求使用它(来自here的原创想法):
private Regex regex =
new Regex(@"\[a\s+href='(?<link>[^']+)'\](?<text>.*?)\[/a\]",
RegexOptions.Compiled);
这将匹配包含链接的字符串中的所有链接,并为每个匹配创建2个命名组:link
和text
现在您可以遍历所有匹配项。每场比赛都会给你一个
foreach (Match match in regex.Matches(stringContainingLinks))
{
string link = match.Groups["link"].Value;
int link_start = match.Groups["link"].Index;
int link_end = match.Groups["link"].Index + link.Length;
string text = match.Groups["text"].Value;
int text_start = match.Groups["text"].Index;
int text_end = match.Groups["text"].Index + text.Length;
// do whatever you want with stringContainingLinks.
// In particular, remove whole `match` ie [a href='...']...[/a]
// and instead put HyperLink with `NavigateUri = link` and
// `Inlines.Add(text)`
// See the answer by Stanislav Kniazev for how to do this
}
注意:在您的自定义ConvertToHyperlinkedText
值转换器中使用此逻辑。
答案 2 :(得分:0)
此版本的另一个版本,与此处的识别格式并不完全相同,但这里是用于自动识别一段文本中的链接并使它们成为超链接的类:
internal class TextBlockExt
{
static Regex _regex =
new Regex(@"http[s]?://[^\s-]+",
RegexOptions.Compiled);
public static readonly DependencyProperty FormattedTextProperty = DependencyProperty.RegisterAttached("FormattedText",
typeof(string), typeof(TextBlockExt), new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.AffectsMeasure, FormattedTextPropertyChanged));
public static void SetFormattedText(DependencyObject textBlock, string value)
{ textBlock.SetValue(FormattedTextProperty, value); }
public static string GetFormattedText(DependencyObject textBlock)
{ return (string)textBlock.GetValue(FormattedTextProperty); }
static void FormattedTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (!(d is TextBlock textBlock)) return;
var formattedText = (string)e.NewValue ?? string.Empty;
string fullText =
$"<Span xml:space=\"preserve\" xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">{formattedText}</Span>";
textBlock.Inlines.Clear();
using (var xmlReader1 = XmlReader.Create(new StringReader(fullText)))
{
try
{
var result = (Span)XamlReader.Load(xmlReader1);
RecognizeHyperlinks(result);
textBlock.Inlines.Add(result);
}
catch
{
formattedText = System.Security.SecurityElement.Escape(formattedText);
fullText =
$"<Span xml:space=\"preserve\" xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">{formattedText}</Span>";
using (var xmlReader2 = XmlReader.Create(new StringReader(fullText)))
{
try
{
dynamic result = (Span) XamlReader.Load(xmlReader2);
textBlock.Inlines.Add(result);
}
catch
{
//ignored
}
}
}
}
}
static void RecognizeHyperlinks(Inline originalInline)
{
if (!(originalInline is Span span)) return;
var replacements = new Dictionary<Inline, List<Inline>>();
var startInlines = new List<Inline>(span.Inlines);
foreach (Inline i in startInlines)
{
switch (i)
{
case Hyperlink _:
continue;
case Run run:
{
if (!_regex.IsMatch(run.Text)) continue;
var newLines = GetHyperlinks(run);
replacements.Add(run, newLines);
break;
}
default:
RecognizeHyperlinks(i);
break;
}
}
if (!replacements.Any()) return;
var currentInlines = new List<Inline>(span.Inlines);
span.Inlines.Clear();
foreach (Inline i in currentInlines)
{
if (replacements.ContainsKey(i)) span.Inlines.AddRange(replacements[i]);
else span.Inlines.Add(i);
}
}
static List<Inline> GetHyperlinks(Run run)
{
var result = new List<Inline>();
var currentText = run.Text;
do
{
if (!_regex.IsMatch(currentText))
{
if (!string.IsNullOrEmpty(currentText)) result.Add(new Run(currentText));
break;
}
var match = _regex.Match(currentText);
if (match.Index > 0)
{
result.Add(new Run(currentText.Substring(0, match.Index)));
}
var hyperLink = new Hyperlink() { NavigateUri = new Uri(match.Value) };
hyperLink.Inlines.Add(match.Value);
hyperLink.RequestNavigate += HyperLink_RequestNavigate;
result.Add(hyperLink);
currentText = currentText.Substring(match.Index + match.Length);
} while (true);
return result;
}
static void HyperLink_RequestNavigate(object sender, System.Windows.Navigation.RequestNavigateEventArgs e)
{
try
{
Process.Start(e.Uri.ToString());
}
catch { }
}
}
使用您只能执行<TextBlock ns:Attached.FormattedText="{Binding Content}" />
而不是<TextBlock Text="{Binding Content}" />
,它将自动识别并激活链接,以及识别诸如<Bold>
之类的常规格式标签。
请注意,这是基于@gwiazdorrr here的答案以及该问题的其他答案;我基本上将它们全部合并为1,并进行了一些递归处理,并且有效! :)。如果需要,这些模式和系统也可以用于识别其他类型的链接或标记。
答案 3 :(得分:0)
XAML:
<TextBlock x:Name="txbLink" Height="30" Width="500" Margin="0,10"/>
C#:
Regex regex = new Regex(@"(?<text1>.*?)\<a\s+href='(?<link>\[^'\]+)'\>(?<textLink>.*?)\</a\>(?<text2>.*)", RegexOptions.Compiled);
string stringContainingLinks = "Click <a href='http://somesite.com'>here</a> for download.";
foreach (Match match in regex.Matches(stringContainingLinks))
{
string text1 = match.Groups["text1"].Value;
string link = match.Groups["link"].Value;
string textLink = match.Groups["textLink"].Value;
string text2 = match.Groups["text2"].Value;
var h = new Hyperlink();
h.NavigateUri = new Uri(link);
h.RequestNavigate += new RequestNavigateEventHandler(Hyperlink_RequestNavigate);
h.Inlines.Add(textLink);
txbLink.Inlines.Add(text1);
txbLink.Inlines.Add(h);
txbLink.Inlines.Add(text2);
}
private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e)
{
Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri));
e.Handled = true;
}