| File: System\Windows\Forms\Controls\PropertyGrid\PropertyGridInternal\HelpPane.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.Drawing; namespace System.Windows.Forms.PropertyGridInternal; /// <summary> /// The help (description) pane optionally shown at the bottom of the <see cref="PropertyGrid"/>. /// </summary> /// <remarks> /// <para> /// <see cref="PropertyGrid.HelpVisible"/> controls the visibility of this control. /// </para> /// </remarks> internal partial class HelpPane : PropertyGrid.SnappableControl { private readonly Label _titleLabel; private readonly Label _descriptionLabel; private string? _fullDescription; private int _lineHeight; private bool _needUpdateUIWithFont = true; private const int LogicalDefaultWidth = 0; private const int LogicalDefaultHeight = 59; private const int MinimumLines = 2; private int _borderSize; private Rectangle _lastClientRectangle = Rectangle.Empty; internal HelpPane(PropertyGrid owner) : base(owner) { using SuspendLayoutScope scope = new(this, performLayout: false); _titleLabel = new() { UseMnemonic = false, Cursor = Cursors.Default }; _descriptionLabel = new() { AutoEllipsis = true, Cursor = Cursors.Default }; UpdateTextRenderingEngine(); Controls.Add(_titleLabel); Controls.Add(_descriptionLabel); Size = new(LogicalToDeviceUnits(LogicalDefaultWidth), LogicalToDeviceUnits(LogicalDefaultHeight)); Text = SR.PropertyGridHelpPaneTitle; SetStyle(ControlStyles.Selectable, false); } private protected override void InitializeControl() => ScaleConstants(); public virtual int Lines { get { UpdateUIWithFont(); return Height / _lineHeight; } set { UpdateUIWithFont(); Size = new(Width, 1 + value * _lineHeight); } } public override int GetOptimalHeight(int width) { UpdateUIWithFont(); // Compute optimal label height as one line only. int height = _titleLabel.Size.Height; // Do this to avoid getting parented to the Parking window. if (OwnerPropertyGrid.IsHandleCreated && !IsHandleCreated) { CreateControl(); } // Compute optimal text height. bool isScalingRequirementMet = ScaleHelper.IsScalingRequirementMet; using Graphics g = _descriptionLabel.CreateGraphicsInternal(); SizeF sizef = PropertyGrid.MeasureTextHelper.MeasureText(OwnerPropertyGrid, g, _titleLabel.Text, Font, width); Size size = Size.Ceiling(sizef); int padding = isScalingRequirementMet ? LogicalToDeviceUnits(2) : 2; height += (size.Height * 2) + padding; return Math.Max(height + 2 * padding, isScalingRequirementMet ? LogicalToDeviceUnits(LogicalDefaultHeight) : LogicalDefaultHeight); } internal virtual void LayoutWindow() { } protected override void OnFontChanged(EventArgs e) { _needUpdateUIWithFont = true; PerformLayout(); base.OnFontChanged(e); } protected override void OnLayout(LayoutEventArgs e) { UpdateUIWithFont(); SetLabelBounds(); _descriptionLabel.Text = _fullDescription; _descriptionLabel.AccessibleName = _fullDescription; // Don't crop the description for accessibility clients base.OnLayout(e); } protected override void OnResize(EventArgs e) { Rectangle currentClientRectangle = ClientRectangle; if (!_lastClientRectangle.IsEmpty && currentClientRectangle.Width > _lastClientRectangle.Width) { Invalidate(new Rectangle( _lastClientRectangle.Width - 1, 0, currentClientRectangle.Width - _lastClientRectangle.Width + 1, _lastClientRectangle.Height)); } if (ScaleHelper.IsScalingRequirementMet) { int oldLineHeight = _lineHeight; _lineHeight = Font.Height + LogicalToDeviceUnits(2); if (oldLineHeight != _lineHeight) { _titleLabel.Location = new(_borderSize, _borderSize); _descriptionLabel.Location = new(_borderSize, _borderSize + _lineHeight); SetLabelBounds(); } } _lastClientRectangle = currentClientRectangle; base.OnResize(e); } private void SetLabelBounds() { Size size = ClientSize; // If the client size is 0, setting this to a negative number will force an extra layout. size.Width = Math.Max(0, size.Width - 2 * _borderSize); size.Height = Math.Max(0, size.Height - 2 * _borderSize); _titleLabel.SetBounds( _titleLabel.Top, _titleLabel.Left, size.Width, Math.Min(_lineHeight, size.Height), BoundsSpecified.Size); _descriptionLabel.SetBounds( _descriptionLabel.Top, _descriptionLabel.Left, size.Width, Math.Max(0, size.Height - _lineHeight - (ScaleHelper.IsScalingRequirementMet ? LogicalToDeviceUnits(1) : 1)), BoundsSpecified.Size); } protected override void OnHandleCreated(EventArgs e) { base.OnHandleCreated(e); UpdateUIWithFont(); } protected override void RescaleConstantsForDpi(int deviceDpiOld, int deviceDpiNew) { base.RescaleConstantsForDpi(deviceDpiOld, deviceDpiNew); ScaleConstants(); } private void ScaleConstants() { const int LogicalBorderSize = 3; _borderSize = LogicalToDeviceUnits(LogicalBorderSize); } public virtual void SetDescription(string? title, string? description) { if (_descriptionLabel.Text != title) { _titleLabel.Text = title; } if (description != _fullDescription) { _fullDescription = description; _descriptionLabel.Text = _fullDescription; // Don't crop the description for accessibility clients. _descriptionLabel.AccessibleName = _fullDescription; } } public override int SnapHeightRequest(int newHeight) { UpdateUIWithFont(); int lines = Math.Max(MinimumLines, newHeight / _lineHeight); return 1 + lines * _lineHeight; } /// <inheritdoc /> protected override AccessibleObject CreateAccessibilityInstance() => new HelpPaneAccessibleObject(this, OwnerPropertyGrid); /// <inheritdoc /> internal override bool SupportsUiaProviders => true; internal void UpdateTextRenderingEngine() { _titleLabel.UseCompatibleTextRendering = OwnerPropertyGrid.UseCompatibleTextRendering; _descriptionLabel.UseCompatibleTextRendering = OwnerPropertyGrid.UseCompatibleTextRendering; } private void UpdateUIWithFont() { if (IsHandleCreated && _needUpdateUIWithFont) { // Some fonts throw because Bold is not a valid option for them. Fail gracefully. try { _titleLabel.Font = new(Font, FontStyle.Bold); } catch (Exception e) when (!e.IsCriticalException()) { } _lineHeight = Font.Height + 2; _titleLabel.Location = new(_borderSize, _borderSize); _descriptionLabel.Location = new(_borderSize, _borderSize + _lineHeight); _needUpdateUIWithFont = false; PerformLayout(); } } }