【问题标题】:RequestNavigate to Hyperlink with page anchor请求导航到带有页面锚点的超链接
【发布时间】:2020-04-05 06:23:06
【问题描述】:

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

在我的测试示例(下面的完整代码)中,Uri 片段没有进入浏览器。
我已经尝试过其他方法来创建超链接,但这已经尽可能接近了。

测试应用:

结果:

MainWindow.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>

MainWindow.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)); }
    }
}

【问题讨论】:

  • 只是另一个想法 - 为什么不将其加载到您的应用程序中?
  • 好吧,也许有点太简单了,但是您是否尝试过将# 替换为%23?适用于我的 Windows cmd/Process.Start()。当您点击 WINLOGO+R 并插入例如:https://de.ryte.com/wiki/Anchor_Tag%23href-Attribut 时也可以使用。
  • @Flithor 好主意。如果使用 WebBrowser 控件,它会很好地工作。然后只需使用带有 URI 参数的webBrowser.Navigate(uri)
  • @Flithor 我同意这将是一个很好的解决方案,但这不是规范。

标签: c# wpf hyperlink


【解决方案1】:

如果你让操作系统自己识别默认浏览器,它似乎会从 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);

如果您想使用用户定义的浏览器而不是硬编码的浏览器,则必须查询 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];
    }
}

在 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");
}

这适用于除Microsoft Edge, which do not allow that at the moment 之外的所有浏览器。 你可以像这样在你的程序中使用:

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);
    }
}

一些额外的答案: How to find default web browser using C#?

【讨论】:

  • 感谢您写得很好的答案。看来操作系统是罪魁祸首。您的解决方法(指定要直接使用的浏览器)完美运行!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-27
  • 1970-01-01
  • 2011-02-05
  • 1970-01-01
相关资源
最近更新 更多