| File: System\Windows\Forms\Controls\PropertyGrid\PropertyGridInternal\CategoryGridEntry.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.Collections.Concurrent; using System.Drawing; namespace System.Windows.Forms.PropertyGridInternal; /// <summary> /// Virtual, collapsible parent <see cref="GridEntry"/>. /// </summary> internal sealed partial class CategoryGridEntry : GridEntry { private readonly string _name; private static readonly ConcurrentDictionary<string, bool> s_categoryStates = []; public CategoryGridEntry(PropertyGrid ownerGrid, GridEntry parent, string name, IEnumerable<GridEntry> children) : base(ownerGrid, parent) { _name = name; s_categoryStates.TryAdd(name, true); IsExpandable = true; ChildCollection = new GridEntryCollection(children); foreach (var child in ChildCollection) { child.ParentGridEntry = this; } InternalExpanded = s_categoryStates[name]; SetFlag(Flags.LabelBold, true); } // We have no value to display for a category entry. internal override bool HasValue => false; protected override void Dispose(bool disposing) { if (disposing) { ChildCollection = null; } base.Dispose(disposing); } // Categories should never dispose public override void DisposeChildren() { } // Don't want this participating in property depth. public override int PropertyDepth => base.PropertyDepth - 1; /// <summary> /// Gets the accessibility object for the current category grid entry. /// </summary> protected override GridEntryAccessibleObject GetAccessibilityObject() => new CategoryGridEntryAccessibleObject(this); protected override Color BackgroundColor => OwnerGridView?.LineColor ?? default; protected override Color LabelTextColor => OwnerGrid.CategoryForeColor; public override bool Expandable => !GetFlagSet(Flags.ExpandableFailed); internal override bool InternalExpanded { set { base.InternalExpanded = value; s_categoryStates[_name] = value; } } public override GridItemType GridItemType => GridItemType.Category; public override string? HelpKeyword => null; public override string PropertyLabel => _name; internal override int PropertyLabelIndent { get { PropertyGridView? gridHost = OwnerGridView; // Give an extra pixel for breathing room. // Calling base.PropertyDepth to avoid the -1 in our override. return 1 + (gridHost?.OutlineIconSize ?? 0) + OutlineIconPadding + (base.PropertyDepth * PropertyGridView.DefaultOutlineIndent); } } public override string GetPropertyTextValue(object? o) => string.Empty; public override Type PropertyType => typeof(void); internal override object? GetValueOwnerInternal() => ParentGridEntry?.GetValueOwnerInternal(); protected override bool CreateChildren(bool diffOldChildren) => true; public override string GetTestingInfo() => $"object = ({FullLabel}), Category = ({PropertyLabel})"; public override void PaintLabel( Graphics g, Rectangle rect, Rectangle clipRect, bool selected, bool paintFullLabel) { base.PaintLabel(g, rect, clipRect, false, true); // Draw the focus rect. if (selected && HasFocus) { bool bold = EntryFlags.HasFlag(Flags.LabelBold); Font font = GetFont(boldFont: bold); int labelWidth = GetLabelTextWidth(PropertyLabel, g, font); int indent = PropertyLabelIndent - 2; Rectangle focusRect = new(indent, rect.Y, labelWidth + 3, rect.Height - 1); if (SystemInformation.HighContrast && !OwnerGrid.HasCustomLineColor) { // Line color is SystemColors.ControlDarkDark in a contrast theme scenario. ControlPaint.DrawFocusRectangle(g, focusRect, SystemColors.ControlText, OwnerGrid.LineColor); } else { ControlPaint.DrawFocusRectangle(g, focusRect); } } // Draw the line along the top. if (ParentGridEntry is not null && ParentGridEntry.GetChildIndex(this) > 0) { using var topLinePen = OwnerGrid.CategorySplitterColor.GetCachedPenScope(); g.DrawLine(topLinePen, rect.X - 1, rect.Y - 1, rect.Width + 2, rect.Y - 1); } } public override void PaintValue( Graphics g, Rectangle rect, Rectangle clipRect, PaintValueFlags paintFlags, string? text) { base.PaintValue(g, rect, clipRect, paintFlags & ~PaintValueFlags.DrawSelected, text); // Draw the line along the top. if (ParentGridEntry is not null && ParentGridEntry.GetChildIndex(this) > 0) { using var topLinePen = OwnerGrid.CategorySplitterColor.GetCachedPenScope(); g.DrawLine(topLinePen, rect.X - 2, rect.Y - 1, rect.Width + 1, rect.Y - 1); } } internal override bool SendNotification(GridEntry entry, Notify notification) => ParentGridEntry?.SendNotification(entry, notification) ?? false; }