텍스트 블록 WPF에 하이퍼링크 추가
db에 몇 가지 텍스트가 있는데 다음과 같습니다.
로렘 입숨 돌로 시트 아멧, 콘셉터터 아디피싱 엘릿.Duis tellus nisl, venatis et pharetra ac, 임시 sed sapien.정수 펠렌테스크 블랜디트 벨릿, 템푸스 우르나 세미퍼 시트 아메트.Duis mollis, libero ut consectetur interdum, massa tellus posuere nisi, eu aliquet elit lacus necerat.코모도 퀀텀을 만들다.
[a href='http://somesite.example]some site[/a]
Nisi sit amet massa gravida fugiat ac sem.에 있는 suspendis.Phaselus ac mauris ipsum, vel auxor odio
질문입니다.어떻게 하면Hyperlink
에 있어서TextBlock
이 목적으로 webBrowser 컨트롤을 사용하지 않습니다.이 컨트롤도 사용하고 싶지 않습니다.https://www.codeproject.com/Articles/33196/WPF-Html-supported-TextBlock
표시는 다소 간단하지만 내비게이션은 또 다른 질문입니다.XAML은 다음과 같습니다.
<TextBlock Name="TextBlockWithHyperlink">
Some text
<Hyperlink
NavigateUri="http://somesite.example"
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.example")
};
hyperLink.Inlines.Add("some site");
hyperLink.RequestNavigate += Hyperlink_RequestNavigate;
TextBlockWithHyperlink.Inlines.Add(hyperLink);
TextBlockWithHyperlink.Inlines.Add(" Some more text");
이러한 상황에서는 Regex를 값 변환기와 함께 사용할 수 있습니다.
고객의 요건에 따라 다음을 사용합니다(여기서 발상).
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
값 변환기
여기서 형식을 인식하는 것과는 완전히 다른 버전이지만 텍스트 내의 링크를 자동으로 인식하여 하이퍼링크를 활성화하기 위한 클래스가 있습니다.
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:TextBlockExt.FormattedText="{Binding Content}" />
대신<TextBlock Text="{Binding Content}" />
링크를 자동으로 인식하고 활성화하며 다음과 같은 일반적인 포맷 태그를 인식합니다.<Bold>
,기타.
이는 @gwiazdorr의 답변과 이 질문에 대한 다른 답변에 기초하고 있습니다.기본적으로 이 모든 것을 1로 조합하여 재귀 처리를 실시하면 효과가 있습니다. :)패턴과 시스템은 필요에 따라 다른 유형의 링크 또는 마크업을 인식하도록 조정할 수도 있습니다.
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.example'>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;
}
언급URL : https://stackoverflow.com/questions/2092890/add-hyperlink-to-textblock-wpf
'sourcecode' 카테고리의 다른 글
다른 클래스에서 실행 중인 다른 스레드에서 UI를 업데이트하는 방법 (0) | 2023.04.28 |
---|---|
이클립스와 같은 Android Studio 바로 가기 (0) | 2023.04.28 |
SQLite3 데이터베이스에서 열 이름 목록을 가져오려면 어떻게 해야 합니까? (0) | 2023.04.23 |
CSS를 사용하여 div를 수직으로 스크롤할 수 있도록 하다 (0) | 2023.04.23 |
Bash 배열에 대한 명령어 출력 읽기 (0) | 2023.04.23 |