| File: System\Windows\Forms\Help\HelpProvider.cs | Web Access |
| Project: src\winforms\src\System.Windows.Forms\System.Windows.Forms.csproj (System.Windows.Forms) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.ComponentModel; using System.Drawing.Design; namespace System.Windows.Forms; /// <summary> /// Provides pop-up or online Help for controls. /// </summary> [ProvideProperty("HelpString", typeof(Control))] [ProvideProperty("HelpKeyword", typeof(Control))] [ProvideProperty("HelpNavigator", typeof(Control))] [ProvideProperty("ShowHelp", typeof(Control))] [ToolboxItemFilter("System.Windows.Forms")] [SRDescription(nameof(SR.DescriptionHelpProvider))] public class HelpProvider : Component, IExtenderProvider { private readonly Dictionary<Control, string?> _helpStrings = []; private readonly Dictionary<Control, bool> _showHelp = []; private readonly List<Control> _boundControls = []; private readonly Dictionary<Control, string?> _keywords = []; private readonly Dictionary<Control, HelpNavigator> _navigators = []; /// <summary> /// Initializes a new instance of the <see cref="HelpProvider"/> class. /// </summary> public HelpProvider() { } /// <summary> /// Gets or sets a string indicating the name of the Help file associated with this /// <see cref="HelpProvider"/> object. /// </summary> [Localizable(true)] [DefaultValue(null)] [Editor($"System.Windows.Forms.Design.HelpNamespaceEditor, {Assemblies.SystemDesign}", typeof(UITypeEditor))] [SRDescription(nameof(SR.HelpProviderHelpNamespaceDescr))] public virtual string? HelpNamespace { get; set; } [SRCategory(nameof(SR.CatData))] [Localizable(false)] [Bindable(true)] [SRDescription(nameof(SR.ControlTagDescr))] [DefaultValue(null)] [TypeConverter(typeof(StringConverter))] public object? Tag { get; set; } /// <summary> /// Determines if the help provider can offer it's extender properties to the specified target /// object. /// </summary> public virtual bool CanExtend(object? target) => target is Control; /// <summary> /// Retrieves the Help Keyword displayed when the user invokes Help for the specified control. /// </summary> [DefaultValue(null)] [Localizable(true)] [SRDescription(nameof(SR.HelpProviderHelpKeywordDescr))] public virtual string? GetHelpKeyword(Control ctl) { ArgumentNullException.ThrowIfNull(ctl); return _keywords.TryGetValue(ctl, out string? value) ? value : null; } /// <summary> /// Retrieves the contents of the pop-up help window for the specified control. /// </summary> [DefaultValue(HelpNavigator.AssociateIndex)] [Localizable(true)] [SRDescription(nameof(SR.HelpProviderNavigatorDescr))] public virtual HelpNavigator GetHelpNavigator(Control ctl) { ArgumentNullException.ThrowIfNull(ctl); return _navigators.TryGetValue(ctl, out HelpNavigator value) ? value : HelpNavigator.AssociateIndex; } /// <summary> /// Retrieves the contents of the pop-up help window for the specified control. /// </summary> [DefaultValue(null)] [Localizable(true)] [SRDescription(nameof(SR.HelpProviderHelpStringDescr))] public virtual string? GetHelpString(Control ctl) { ArgumentNullException.ThrowIfNull(ctl); return _helpStrings.TryGetValue(ctl, out string? value) ? value : null; } /// <summary> /// Retrieves a value indicating whether Help displays for the specified control. /// </summary> [Localizable(true)] [SRDescription(nameof(SR.HelpProviderShowHelpDescr))] public virtual bool GetShowHelp(Control ctl) { ArgumentNullException.ThrowIfNull(ctl); return _showHelp.TryGetValue(ctl, out bool value) && value; } /// <summary> /// Handles the help event for any bound controls. /// </summary> private void OnControlHelp(object? sender, HelpEventArgs hevent) { if (sender is not Control ctl) { return; } string? helpString = GetHelpString(ctl); string? keyword = GetHelpKeyword(ctl); HelpNavigator navigator = GetHelpNavigator(ctl); if (!GetShowHelp(ctl) || hevent is null) { return; } if (Control.MouseButtons != MouseButtons.None && !string.IsNullOrEmpty(helpString)) { Help.ShowPopup(ctl, helpString, hevent.MousePos); hevent.Handled = true; return; } // If we have a help file, and help keyword we try F1 help next if (HelpNamespace is not null) { if (!string.IsNullOrEmpty(keyword)) { Help.ShowHelp(ctl, HelpNamespace, navigator, keyword); } else { Help.ShowHelp(ctl, HelpNamespace, navigator); } hevent.Handled = true; return; } // So at this point we don't have a help keyword, so try to display the whats this help if (!string.IsNullOrEmpty(helpString)) { Help.ShowPopup(ctl, helpString, hevent.MousePos); hevent.Handled = true; } } /// <summary> /// Handles the help event for any bound controls. /// </summary> private void OnQueryAccessibilityHelp(object? sender, QueryAccessibilityHelpEventArgs e) { if (sender is not Control ctl) { return; } e.HelpString = GetHelpString(ctl); e.HelpKeyword = GetHelpKeyword(ctl); e.HelpNamespace = HelpNamespace; } /// <summary> /// Specifies a Help string associated with a control. /// </summary> public virtual void SetHelpString(Control ctl, string? helpString) { ArgumentNullException.ThrowIfNull(ctl); _helpStrings[ctl] = helpString; if (!string.IsNullOrEmpty(helpString)) { SetShowHelp(ctl, true); } UpdateEventBinding(ctl); } /// <summary> /// Specifies the Help keyword to display when the user invokes Help for a control. /// </summary> public virtual void SetHelpKeyword(Control ctl, string? keyword) { ArgumentNullException.ThrowIfNull(ctl); _keywords[ctl] = keyword; if (!string.IsNullOrEmpty(keyword)) { SetShowHelp(ctl, true); } UpdateEventBinding(ctl); } /// <summary> /// Specifies the Help keyword to display when the user invokes Help for a control. /// </summary> public virtual void SetHelpNavigator(Control ctl, HelpNavigator navigator) { ArgumentNullException.ThrowIfNull(ctl); SourceGenerated.EnumValidator.Validate(navigator, nameof(navigator)); _navigators[ctl] = navigator; SetShowHelp(ctl, true); UpdateEventBinding(ctl); } /// <summary> /// Specifies whether Help is displayed for a given control. /// </summary> public virtual void SetShowHelp(Control ctl, bool value) { ArgumentNullException.ThrowIfNull(ctl); _showHelp[ctl] = value; UpdateEventBinding(ctl); } /// <summary> /// Used by the designer /// </summary> internal bool ShouldSerializeShowHelp(Control ctl) { ArgumentNullException.ThrowIfNull(ctl); return _showHelp.ContainsKey(ctl); } /// <summary> /// Used by the designer /// </summary> public virtual void ResetShowHelp(Control ctl) { ArgumentNullException.ThrowIfNull(ctl); _showHelp.Remove(ctl); } /// <summary> /// Binds/unbinds event handlers to ctl /// </summary> private void UpdateEventBinding(Control ctl) { bool showHelp = GetShowHelp(ctl); bool isBound = _boundControls.Contains(ctl); if (showHelp && !isBound) { ctl.HelpRequested += OnControlHelp; ctl.QueryAccessibilityHelp += OnQueryAccessibilityHelp; _boundControls.Add(ctl); } else if (!showHelp && isBound) { ctl.HelpRequested -= OnControlHelp; ctl.QueryAccessibilityHelp -= OnQueryAccessibilityHelp; _boundControls.Remove(ctl); } } /// <summary> /// Returns a string representation for this control. /// </summary> public override string ToString() => $"{base.ToString()}, HelpNamespace: {HelpNamespace}"; }