RequestNavigate 到带有页面锚点的超链接

Oku*_*ott 2 c# wpf hyperlink

我需要打开一个本地 .HTM 文件并导航到特定的锚点名称。
在这种情况下,它是一个包含 1,000 多个警报/锚点的警报信息文件。

在我的测试示例(下面的完整代码)中,Uri 片段没有进入浏览器。
我尝试了其他创建超链接的方法,但这是我所能得到的。

测试应用程序:
测试应用

结果:
测试结果

主窗口.xaml

<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>
Run Code Online (Sandbox Code Playgroud)

主窗口.xaml.cs

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)); }
    }
}
Run Code Online (Sandbox Code Playgroud)

Arn*_*lay 6

似乎如果您让操作系统识别默认浏览器本身,它将从 URI 中删除锚点。

您需要使用以下重载Process.Start来指定可执行文件和参数:

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);
Run Code Online (Sandbox Code Playgroud)

如果要使用用户定义的浏览器而不是硬编码的浏览器,则必须查询 Windows 注册表以检索它。

例如,在旧版本的 Windows 上(我认为在 Vista 之前),您必须使用以下注册表项:HKEY_CLASSES_ROOT\http\shell\open\command. 在以后的版本中,此键包含默认浏览器(如果浏览器未进行任何更改)。

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];
    }
}
Run Code Online (Sandbox Code Playgroud)

在 Windows 10 上,由于允许选择默认应用程序的应用程序启动器,它有点复杂。要检索用户选择的浏览器,您必须查询以下注册表项:HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.html\UserChoice. 如果密钥不存在,您必须回退到前面提到的密钥: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");
}
Run Code Online (Sandbox Code Playgroud)

这将适用于除Microsoft Edge之外的所有浏览器,目前还不允许这样做。你可以在你的程序中这样使用:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

一些额外的答案: 如何使用 C# 找到默认的 Web 浏览器?