I have spent the last few hours trying to do something I thought would be basic stuff in my C# Windows Form application - to have a RichTextBox
with embedded links. However, this seems to be far more complicated than anticipated, and I would appreciate some hints on this.
Please note that I am not sure if RTF and a RichTextBox
is the one-and-only solution for me here, but my end-goal is that I can create something like this below:
So, a list of either web links or local files on system, and then I can of course click it and it will open. Some styling is needed also, like font-weight and bullets etc.
What I have so far is a RichTextBox
named richTextBoxRessources
.
I have tried this RTF code, and a million combinations in here:
string link2 = ";;
string name2 = "My Link";
StringBuilder rtf = new StringBuilder();
rtf.Append(@"{\rtf1\ansi");
rtf.Append(@"{\fonttbl\f0\fnil\fcharset0 Calibri;}");
rtf.Append(@"{\colortbl ;\red0\green0\blue255;}");
rtf.Append(@"\viewkind4\uc1\pard\f0\fs20 ");
rtf.Append($@"{{\field{{\*\fldinst HYPERLINK ""{link2}""}}{{\fldrslt{{\ul\cf1 {name2}}}}}}}");
rtf.Append(@"\par}");
richTextBoxRessources.Rtf = rtf.ToString();
Though it looks like a link in the RichTextBox
, then it does not react when clicking in it.
Do note that I would need multiple links - not only one.
In my main form constructor I of course has its event-listener defined:
richTextBoxRessources.LinkClicked += richTextBoxRessources_LinkClicked;
And then its code:
private void richTextBoxRessources_LinkClicked(object sender, LinkClickedEventArgs e)
{
Debug.WriteLine("Break-point set here");
}
As you can see in the text then I have just placed a break-point in here, but it never reaches in here, which is my problem.
I have also tried looking in to alternatives like the NuGet
package EXTENDED Version of Extended Rich Text Box or Links with arbitrary text in a RichTextBox, but these I could not get working either.
I assume I must to do it with RTF code, as I need to do some bullets and font-weight also, but for now I am focusing on the embedded links.
Anyone have some good ideas for my embedded link problem?
UPDATE 1
I did find a possible "helper" for this, in this answer to Getting Hyperlinks Working in Rich Text Box Using RTF, but this is merely a "try and see if this is working", and no explanation for RTF.
- Create a Word file with the layout and links you want
- Copy/paste this to Wordpad
- Save as RTF file
- Load RTF file in text-editor and copy the RTF cod
- Insert RTF code in
RichTextBox
This actually does make the web link clickable - but ONLY the first link!? All other links looks like normal links, but nothing happens when I click them - only the first link works.
This is my test code for it:
StringBuilder rtf = new StringBuilder();
rtf.Append("{\\rtf1\\ansi\\ansicpg1252\\deff0\\nouicompat\\deflang1033{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 Calibri; } {\\f1\\fnil\\fcharset0 Calibri; } {\\f2\\fnil\\fcharset2 Symbol; } }");
rtf.Append("{\\colortbl;\\red0\\green0\\blue255;\\red5\\green99\\blue193; }");
rtf.Append("{\\*\\generator Riched20 10.0.19041}\\viewkind4\\uc1");
rtf.Append("\\pard\\widctlpar\\sa160\\sl252\\slmult1\\kerning2\\f0\\fs22\\lang1030 Header 1:\\par");
rtf.Append("");
rtf.Append("\\pard{\\pntext\\f2\\'B7\\tab}{\\*\\pn\\pnlvlblt\\pnf2\\pnindent0{\\pntxtb\\'B7}}\\widctlpar\\fi-360\\li720\\sa160\\sl252\\slmult1 {{\\field{\\*\\fldinst{HYPERLINK \"https://link1\"}}{\\fldrslt{\\ul\\cf1\\cf2\\ul Link 1}}}}\\f0\\fs22\\par");
rtf.Append("{\\pntext\\f2\\'B7\\tab}{{\\field{\\*\\fldinst{HYPERLINK \"https://link2\"}}{\\fldrslt{\\ul\\cf1\\cf2\\ul Link 2}}}}\\f0\\fs22\\par");
rtf.Append("");
rtf.Append("\\pard\\widctlpar\\sa160\\sl252\\slmult1 Header 2:\\par");
rtf.Append("");
rtf.Append("\\pard{\\pntext\\f2\\'B7\\tab}{\\*\\pn\\pnlvlblt\\pnf2\\pnindent0{\\pntxtb\\'B7}}\\widctlpar\\fi-360\\li720\\sa160\\sl252\\slmult1 {{\\field{\\*\\fldinst{HYPERLINK \"https://link3\"}}{\\fldrslt{\\ul\\cf1\\cf2\\ul Link 3}}}}\\f0\\fs22\\par");
rtf.Append("");
rtf.Append("\\pard\\sa200\\sl276\\slmult1\\kerning0\\f1\\lang6\\par");
rtf.Append("}");
richTextBoxRessources.Rtf = rtf.ToString();
Someone in comment has suggested to look into "using HTML with a web browser control such as WebView2" - this method I don't know, but I will for sure look in to this, but I am fearing for the local links then.
UPDATE 2
i have tested the Microsoft.Web.WebView2
NuGet package, and this could work fine for web links, but as suspected then local file links does not work - it does not trigger the click-event for any files.
This is my code:
private async void InitializeWebView()
{
await webView21.EnsureCoreWebView2Async(null);
// Handle navigation events
webView21.CoreWebView2.NavigationStarting += (sender, args) =>
{
Debug.WriteLine("NavigationStarting: " + args.Uri);
if (args.Uri.StartsWith("file://", StringComparison.OrdinalIgnoreCase))
{
args.Cancel = true;
string localPath = new Uri(args.Uri).LocalPath;
Process.Start(new ProcessStartInfo(localPath) { UseShellExecute = true });
}
};
// HTML
string htmlContent = @"
<html>
<head>
<meta charset='UTF-8'>
<title>Local File Test</title>
</head>
<body>
<h1>Try opening local files:</h1>
<ul>
<li><a href='file:///C:\\GlDifxCmd.log'>Open local log file</a></li>
<li><a href=''>Google</a></li>
</ul>
</body>
</html>";
webView21.NavigateToString(htmlContent);
}
The Debug.WriteLine
is triggered at the web link, but not for the file link.
UPDATE 3
I am opting in for the an alternative solution, as handling RTF seems a little too complicated and weird for my taste. Instead of RTF and RichTextBox
, I ended up using WebView2
, which is a Microsoft NuGet package which will support internal generated HTML pages.
View the accepted answer below.
I have spent the last few hours trying to do something I thought would be basic stuff in my C# Windows Form application - to have a RichTextBox
with embedded links. However, this seems to be far more complicated than anticipated, and I would appreciate some hints on this.
Please note that I am not sure if RTF and a RichTextBox
is the one-and-only solution for me here, but my end-goal is that I can create something like this below:
So, a list of either web links or local files on system, and then I can of course click it and it will open. Some styling is needed also, like font-weight and bullets etc.
What I have so far is a RichTextBox
named richTextBoxRessources
.
I have tried this RTF code, and a million combinations in here:
string link2 = "https://whatever.dk";
string name2 = "My Link";
StringBuilder rtf = new StringBuilder();
rtf.Append(@"{\rtf1\ansi");
rtf.Append(@"{\fonttbl\f0\fnil\fcharset0 Calibri;}");
rtf.Append(@"{\colortbl ;\red0\green0\blue255;}");
rtf.Append(@"\viewkind4\uc1\pard\f0\fs20 ");
rtf.Append($@"{{\field{{\*\fldinst HYPERLINK ""{link2}""}}{{\fldrslt{{\ul\cf1 {name2}}}}}}}");
rtf.Append(@"\par}");
richTextBoxRessources.Rtf = rtf.ToString();
Though it looks like a link in the RichTextBox
, then it does not react when clicking in it.
Do note that I would need multiple links - not only one.
In my main form constructor I of course has its event-listener defined:
richTextBoxRessources.LinkClicked += richTextBoxRessources_LinkClicked;
And then its code:
private void richTextBoxRessources_LinkClicked(object sender, LinkClickedEventArgs e)
{
Debug.WriteLine("Break-point set here");
}
As you can see in the text then I have just placed a break-point in here, but it never reaches in here, which is my problem.
I have also tried looking in to alternatives like the NuGet
package EXTENDED Version of Extended Rich Text Box or Links with arbitrary text in a RichTextBox, but these I could not get working either.
I assume I must to do it with RTF code, as I need to do some bullets and font-weight also, but for now I am focusing on the embedded links.
Anyone have some good ideas for my embedded link problem?
UPDATE 1
I did find a possible "helper" for this, in this answer to Getting Hyperlinks Working in Rich Text Box Using RTF, but this is merely a "try and see if this is working", and no explanation for RTF.
- Create a Word file with the layout and links you want
- Copy/paste this to Wordpad
- Save as RTF file
- Load RTF file in text-editor and copy the RTF cod
- Insert RTF code in
RichTextBox
This actually does make the web link clickable - but ONLY the first link!? All other links looks like normal links, but nothing happens when I click them - only the first link works.
This is my test code for it:
StringBuilder rtf = new StringBuilder();
rtf.Append("{\\rtf1\\ansi\\ansicpg1252\\deff0\\nouicompat\\deflang1033{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 Calibri; } {\\f1\\fnil\\fcharset0 Calibri; } {\\f2\\fnil\\fcharset2 Symbol; } }");
rtf.Append("{\\colortbl;\\red0\\green0\\blue255;\\red5\\green99\\blue193; }");
rtf.Append("{\\*\\generator Riched20 10.0.19041}\\viewkind4\\uc1");
rtf.Append("\\pard\\widctlpar\\sa160\\sl252\\slmult1\\kerning2\\f0\\fs22\\lang1030 Header 1:\\par");
rtf.Append("");
rtf.Append("\\pard{\\pntext\\f2\\'B7\\tab}{\\*\\pn\\pnlvlblt\\pnf2\\pnindent0{\\pntxtb\\'B7}}\\widctlpar\\fi-360\\li720\\sa160\\sl252\\slmult1 {{\\field{\\*\\fldinst{HYPERLINK \"https://link1\"}}{\\fldrslt{\\ul\\cf1\\cf2\\ul Link 1}}}}\\f0\\fs22\\par");
rtf.Append("{\\pntext\\f2\\'B7\\tab}{{\\field{\\*\\fldinst{HYPERLINK \"https://link2\"}}{\\fldrslt{\\ul\\cf1\\cf2\\ul Link 2}}}}\\f0\\fs22\\par");
rtf.Append("");
rtf.Append("\\pard\\widctlpar\\sa160\\sl252\\slmult1 Header 2:\\par");
rtf.Append("");
rtf.Append("\\pard{\\pntext\\f2\\'B7\\tab}{\\*\\pn\\pnlvlblt\\pnf2\\pnindent0{\\pntxtb\\'B7}}\\widctlpar\\fi-360\\li720\\sa160\\sl252\\slmult1 {{\\field{\\*\\fldinst{HYPERLINK \"https://link3\"}}{\\fldrslt{\\ul\\cf1\\cf2\\ul Link 3}}}}\\f0\\fs22\\par");
rtf.Append("");
rtf.Append("\\pard\\sa200\\sl276\\slmult1\\kerning0\\f1\\lang6\\par");
rtf.Append("}");
richTextBoxRessources.Rtf = rtf.ToString();
Someone in comment has suggested to look into "using HTML with a web browser control such as WebView2" - this method I don't know, but I will for sure look in to this, but I am fearing for the local links then.
UPDATE 2
i have tested the Microsoft.Web.WebView2
NuGet package, and this could work fine for web links, but as suspected then local file links does not work - it does not trigger the click-event for any files.
This is my code:
private async void InitializeWebView()
{
await webView21.EnsureCoreWebView2Async(null);
// Handle navigation events
webView21.CoreWebView2.NavigationStarting += (sender, args) =>
{
Debug.WriteLine("NavigationStarting: " + args.Uri);
if (args.Uri.StartsWith("file://", StringComparison.OrdinalIgnoreCase))
{
args.Cancel = true;
string localPath = new Uri(args.Uri).LocalPath;
Process.Start(new ProcessStartInfo(localPath) { UseShellExecute = true });
}
};
// HTML
string htmlContent = @"
<html>
<head>
<meta charset='UTF-8'>
<title>Local File Test</title>
</head>
<body>
<h1>Try opening local files:</h1>
<ul>
<li><a href='file:///C:\\GlDifxCmd.log'>Open local log file</a></li>
<li><a href='https://www.google'>Google</a></li>
</ul>
</body>
</html>";
webView21.NavigateToString(htmlContent);
}
The Debug.WriteLine
is triggered at the web link, but not for the file link.
UPDATE 3
I am opting in for the an alternative solution, as handling RTF seems a little too complicated and weird for my taste. Instead of RTF and RichTextBox
, I ended up using WebView2
, which is a Microsoft NuGet package which will support internal generated HTML pages.
View the accepted answer below.
Share Improve this question edited Mar 25 at 9:37 Beauvais asked Mar 15 at 0:09 BeauvaisBeauvais 2,3195 gold badges34 silver badges70 bronze badges 8 | Show 3 more comments1 Answer
Reset to default 0As suggested by one in the comments, then an alternative solution could be using WebView2
, which is an internal rendered web page. I did not know this was a possibility, but now knowing this option, then I would prefer this solution over handling the weird RTF code.
I have settled for this solution, giving me this output here in my application:
I can tweak the layout easily, as this is web page rendering and by then quite easy.
The only anomaly is the browser engine generated "hover over link view", which looks a little weird in a Windows application (as shown by red arrow), but I assume this is just how it is, and that it cannot easily be hidden, as it is for the purpose of user security (to view link before clicking).
WebView2
handles also local files nicely.
My code is now this, but you will need to add the NuGet package named WebView2
from Microsoft, and you need to add a WebView2 component somewhere in your form (in my example it is named webView21
):
private async void InitializeTabRessources()
{
await webView21.EnsureCoreWebView2Async(null);
webView21.CoreWebView2.WebMessageReceived += (sender, args) =>
{
string message = args.TryGetWebMessageAsString();
if (message.StartsWith("openFile:"))
{
string fileUrl = message.Substring("openFile:".Length);
Process.Start(new ProcessStartInfo(new Uri(fileUrl).LocalPath) { UseShellExecute = true });
}
};
webView21.CoreWebView2.NewWindowRequested += (sender, args) =>
{
args.Handled = true; // Prevent the default behavior
Process.Start(new ProcessStartInfo(args.Uri) { UseShellExecute = true });
};
// HTML code that will get internally rendered
string htmlContent = @"
<html>
<head>
<meta charset='UTF-8'>
<script>
document.addEventListener('click', function(e) {
var target = e.target;
if (target.tagName.toLowerCase() === 'a' && target.href.startsWith('file://')) {
e.preventDefault();
window.chrome.webview.postMessage('openFile:' + target.href);
}
});
</script>
</head>
<body>
<h1>Links</h1>
<h2>Troubleshooting</h2>
<ul>
<li><a href='https://www.google' target='_blank'>Web link 1</a></li>
<li><a href='https://www.microsoft' target='_blank'>Web link 2</a></li>
</ul>
<h2>Documentation</h2>
<ul>
<li><a href='https://www.google' target='_blank'>Web link 3</a></li>
<li><a href='https://www.microsoft' target='_blank'>Web link 4</a></li>
</ul>
<h1>Local files</h1>
<h2>Troubleshooting</h2>
<ul>
<li><a href='file:///C:/GlDifxCmd.log' target='_blank'>Local File 1</a></li>
</ul>
</body>
</html>
";
webView21.NavigateToString(htmlContent);
}
{file.Name}
withfile:////etc.
, it should work. Otherwise, you have to setup aCHARFORMAT2
struct and call SendMessage() withEM_SETCHARFORMAT
to setup the link (thedwEffect
member must containCFE_LINK
, I don't remember whatdwMask
should be set to. See the docs) – Jimi Commented Mar 15 at 1:22file://
part works already fine ;-) It is the web links that I cannot get working, but I will clarify this in my text. – Beauvais Commented Mar 15 at 9:11