Reputation: 3897
I need to open a local .HTM file and navigate to a specific anchor name.
In this case it is an alarm information file with over 1,000 alarms / anchors.
In my test example (full code below) the Uri Fragment doesn't make it into the browser.
I have tried other ways of creating the hyperlink but this is as close as I could get.
<Window x:Class="HyperlinkWithPageAnchor.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="100" Width="200">
<Grid>
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center">
<Hyperlink NavigateUri="{Binding HyperlinkNavUri}" RequestNavigate="Hyperlink_RequestNavigate">
<TextBlock Text="Link Text"/>
</Hyperlink>
</TextBlock>
</Grid>
</Window>
namespace HyperlinkWithPageAnchor
{
using System;
using System.Windows;
using System.ComponentModel;
using System.Windows.Navigation;
public partial class MainWindow : Window, INotifyPropertyChanged
{
private Uri _hyperlinkNavUri;
public Uri HyperlinkNavUri
{
get { return _hyperlinkNavUri; }
set { _hyperlinkNavUri = value; OnPropertyChanged(nameof(HyperlinkNavUri)); }
}
public MainWindow()
{
InitializeComponent(); DataContext = this;
// Desired Address: file:///C:/OSP-P/P-MANUAL/MPA/ENG/ALARM-A.HTM#1101
UriBuilder uBuild = new UriBuilder(new Uri("file://"));
uBuild.Path = @"C:\OSP-P\P-MANUAL\MPA\ENG\ALARM-A.HTM";
uBuild.Fragment = "1101";
HyperlinkNavUri = uBuild.Uri;
}
private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e)
{
try { string link = e.Uri.ToString(); MessageBox.Show(link); System.Diagnostics.Process.Start(link); }
catch (Exception ex) { MessageBox.Show(ex.Message); }
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string name) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); }
}
}
Upvotes: 2
Views: 745
Reputation: 3970
It seems that if you let the OS identify the default browser itself, it will remove the anchor from the URI.
You need to use the following overload of Process.Start
which allows to specify the executable and the parameters:
ProcessStartInfo processStartInfo = new ProcessStartInfo();
processStartInfo.FileName = @"C:\Program Files\Internet Explorer\iexplore.exe";
processStartInfo.Arguments = "file:///C:/OSP-P/P-MANUAL/MPA/ENG/ALARM-A.HTM#1101";
Process.Start(processStartInfo);
If you want to use browser defined by the user instead of an hard-coded one, you will have to query the Windows Registry in order to retrieve it.
For example on old version of windows (before Vista I think), you have to use the following registry key: HKEY_CLASSES_ROOT\http\shell\open\command
. On later release, this key contains the default browser (if the browser does not made any change).
private string GetDefaultBrowser()
{
string regKey = @"HTTP\shell\open\command";
using (RegistryKey registrykey = Registry.ClassesRoot.OpenSubKey(regKey, false))
{
return ((string)registrykey.GetValue(null, null)).Split('"')[1];
}
}
On Windows 10, it is a bit more complex due to the application launcher that allows to select the default application. To retrieve the browser chosen by the user, you have to query the following registry key: HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.html\UserChoice
. It the key does not exist you have to fallback on the previously mentioned key: HKEY_CLASSES_ROOT\http\shell\open\command
.
private string GetDefaultBrowserOnWin10()
{
string execPath;
try
{
string extension = ".htm"; // either .htm or .html
RegistryKey propertyBag = Registry.CurrentUser.OpenSubKey($@"Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\{extension}\UserChoice", false);
var browserProgId = propertyBag.GetValue("ProgId").ToString(); ;
using (RegistryKey execCommandKey = Registry.ClassesRoot.OpenSubKey(browserProgId + @"\shell\open\command", false))
{
execPath = execCommandKey.GetValue(null).ToString().ToLower().Replace("\"", "");
if (IsDefaultLauncherApp(execPath))
{
System.Diagnostics.Debug.WriteLine("No user-defined browser or IE selected; anchor will be lost.");
}
}
if (!execPath.EndsWith("exe"))
{
execPath = execPath.Substring(0, execPath.LastIndexOf(".exe") + 4);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
execPath = GetDefaultBrowser();
}
return execPath;
}
private bool IsDefaultLauncherApp(string appPath)
{
return appPath.Contains("launchwinapp.exe");
}
This will work for all browsers except Microsoft Edge, which do not allow that at the moment. You can use in you program like this:
private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e)
{
try {
string link = e.Uri.ToString();
System.Diagnostics.ProcessStartInfo processStartInfo = new System.Diagnostics.ProcessStartInfo();
processStartInfo.FileName = GetDefaultBrowserOnWin10();
processStartInfo.Arguments = link;
System.Diagnostics.Process.Start(processStartInfo);
} catch (Exception ex) {
MessageBox.Show(ex.Message);
}
}
Some additional answers: How to find default web browser using C#?
Upvotes: 7