HelpProvider在某些控件上忽略了表单的HelpTopic

问题描述

我正在研究的软件项目遇到了令人沮丧的问题。我得到了各种形式的设置帮助,例如,如果按F1键,将打开应用程序的CHM文件

我希望它始终打开与当前表单相关的主题,但是当前它打开的位置取决于表单的焦点。如果重点关注某些字段,它将在帮助文档第一页的顶部打开;如果其他字段处于焦点位置,它将正确打开与当前表单相关的页面标题

对于各种表单,我都有以下设计器代码,而我只是在表单本身上设置了HelpKeyword,而不是表单的任何控件。

this.helpProvider.HelpNamespace = @"Path\To\ChmFile.chm";
this.helpProvider.SetHelpKeyword(this,"TopicName.htm#heading_name");
this.helpProvider.SetHelpNavigator(this,System.Windows.Forms.HelpNavigator.Topic);

根据实验,我确定带有SetShowHelp(false)Enabled = false的项目是唯一显示正确的chm帮助位置的项目。当按F1使其焦点对准时(如果它们可以保持焦点),或者使用“这是什么”帮助光标按它们时,将适用此条件。

例如:

  • 如果焦点位于主对话框的第一个控件(一个具有HelpString的TextBox,它隐式设置ShowHelp),然后按F1键,我将被发送到整个应用程序帮助页面(异常行为)。
  • 如果焦点位于没有关联帮助字符串的主对话框TextBox上,然后按F1键,则会在主对话框的标题显示“对话框”帮助页面(期望的行为)。

到目前为止,我发现的唯一解决方法是在每个带有HelpTopic的控件上同时设置HelpNavigatorHelpString,但这是非常笨拙的操作,很难实现维持。

说明

我有意同时使用“这是什么?”帮助和F1帮助使用相同的形式。我不会接受一种解决方案,该解决方案说要禁用窗体上的所有控件的“这是什么”帮助,以便允许F1帮助起作用。对于此应用程序,交互式控件必须具有帮助工具提示 ,并且每个对话框在帮助文档中都必须有一个帮助部分。

如果无法使这两个帮助功能很好地协同工作,我将接受一种有效的解决方法,该方法不会像上述解决方法那样牺牲可维护性。

解决方法

只有在您澄清之后,我才能够完全理解您的问题并重现该问题。我以前不知道这种行为。 在Windows 10 PC上使用Visual Studio 2019具有相同的不良行为-无论是在Form_Load事件中进行编码还是在设计器代码中借助IDE(集成开发环境)进行编码,都无关紧要。

经过几个小时的实验(针对重现的问题),我希望将其范围缩小到完全不知道真正原因的地方。

通过实验,我已经完成了以下步骤和思想-仅供参考(请参见下面列表中的特殊说明):

  • HelpNavigator枚举的默认值为AssociateIndex。如果您不小心设置了SetShowHelp = True,并且缺少必需的属性,则对“索引”选项卡的调用可能会失败,破坏某些内容并转到CHM的主页主题。如果您的CHM中没有索引标签,则会出现另一个问题。
  • 我删除或重命名了文件 hh.dat 几个例程,以将系统上的所有(!)CHM窗口重置为其默认设置。当您下次打开任何.chm文件时,Windows将创建hh.dat的新版本。您会在C:\Users\%username%\AppData\Roaming\Microsoft\HTML Help找到hh.dat。 但是--在第一个测试阶段中,现有问题没有成功。
  • 仅用于更多测试(以后不再需要代码),我尝试了是否触发了Form3_HelpRequested。 但是-在第一个测试阶段不起作用。
    private void Form1_HelpRequested(object sender,HelpEventArgs hlpevent)
    {
      // do whatever you're gonna do here
      DialogResult dr = MessageBox.Show("HelpRequested on Form1 was fired!\n\nOpen CHM help?","Test case",MessageBoxButtons.YesNo);
      switch (dr)
      {
        case DialogResult.Yes:
          // FALSE will also open any associated help file 
          hlpevent.Handled = false;
          break;
        case DialogResult.No:
          // TRUE will prevent windows from also opening any associated help file
          hlpevent.Handled = true;
          break;
      }
  • 最后一个困难的步骤是,我删除了HelpProvider组件,再次将其插入并再次正确设置了所有属性。 现在-它正在为我工​​作。具有属性ShowHelp=True的控件现在显示分配的主题,具有属性ShowHelp=False的控件现在显示窗体的帮助主题。

您知道-这可能是一个复杂的步骤,应首先在测试环境中完成。确保正确设置了所有属性,并且可以通过HelpKeyword在CHM中访问该主题。

// Tell the HelpProvider what controls to provide help for,and what the help string is.

this.helpProvider1.SetShowHelp(this.cityTextBox,true);
this.helpProvider1.SetHelpNavigator(this.cityTextBox,HelpNavigator.Topic); // make sure to set "Topic"
this.helpProvider1.SetHelpKeyword(this.cityTextBox,@"/Garden/flowers.htm");
this.helpProvider1.SetHelpString(this.cityTextBox,"Enter the city here.");

提供城市文本框焦点和 F1 后,将显示帮助查看器窗口。在第二步中使用“这是什么” 按钮将导致:

enter image description here


tl; dr

通过设计者代码或程序代码对属性的定义更多地取决于个人喜好。我自己更喜欢在程序代码中设置值,而不是通过Visual Studio的控件属性窗口来设置。

如果在此处将帮助功能的所有控件属性添加为代码,则可以轻松注释掉以解决问题。在具有许多控件的表单中,将代码的一部分保存到外部并稍后再插入它们会更容易。但是正如我所说-每个人都喜欢它。

// set F1 help topic for first form
private void Form1_Load(object sender,EventArgs e)
{
  helpProvider1.SetHelpNavigator(this,HelpNavigator.Topic);
  helpProvider1.SetHelpKeyword(this,@"/HTMLHelp_Examples/Jump_to_anchor.htm#SecondAnchor");
}

顺便说一句-“这是什么?”大型程序的帮助意味着付出巨大的努力,而根据我的经验,帮助创作(CHM)的使用越来越少。例如,这种帮助自Visual Basic 6起就有很长的历史。如今,您通常只为表单或对话框找到一个帮助主题,其中解释了单个控件。然后,您描述的问题根本不会出现。

仅供参考-在早期,需要ALIAS和MAP文件,TopicId可能在今天使用它们。这两个文件的目的是简化开发人员和帮助作者之间的协调。映射文件将ID链接到地图编号-通常,开发人员可以轻松创建该ID,并将其传递给帮助作者。然后,帮助作者创建一个别名文件,将ID链接到主题名称。