| File: System\Windows\Forms\Design\SplitterPanelDesigner.cs | Web Access |
| Project: src\winforms\src\System.Windows.Forms.Design\src\System.Windows.Forms.Design.csproj (System.Windows.Forms.Design) |
// 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; using System.ComponentModel; using System.ComponentModel.Design; using System.Drawing; using System.Drawing.Drawing2D; namespace System.Windows.Forms.Design; /// <summary> /// This class handles all design time behavior for the panel class. /// This draws a visible border on the panel if it doesn't have a border /// so the user knows where the boundaries of the panel lie. /// </summary> internal class SplitterPanelDesigner : PanelDesigner { private IDesignerHost? _designerHost; private SplitContainerDesigner? _splitContainerDesigner; private SplitterPanel? _splitterPanel; private bool _selected; public override bool CanBeParentedTo(IDesigner parentDesigner) { return (parentDesigner is SplitContainerDesigner); } protected override InheritanceAttribute? InheritanceAttribute => _splitterPanel is not null && _splitterPanel.Parent is not null ? (InheritanceAttribute?)TypeDescriptor.GetAttributes(_splitterPanel.Parent)[typeof(InheritanceAttribute)] : base.InheritanceAttribute; internal bool Selected { get => _selected; set { _selected = value; if (_selected) { DrawSelectedBorder(); } else { EraseBorder(); } } } protected override void OnDragEnter(DragEventArgs de) { if (InheritanceAttribute == InheritanceAttribute.InheritedReadOnly) { de.Effect = DragDropEffects.None; return; } base.OnDragEnter(de); } protected override void OnDragOver(DragEventArgs de) { if (InheritanceAttribute == InheritanceAttribute.InheritedReadOnly) { de.Effect = DragDropEffects.None; return; } base.OnDragOver(de); } protected override void OnDragLeave(EventArgs e) { if (InheritanceAttribute == InheritanceAttribute.InheritedReadOnly) { return; } base.OnDragLeave(e); } protected override void OnDragDrop(DragEventArgs de) { if (InheritanceAttribute == InheritanceAttribute.InheritedReadOnly) { de.Effect = DragDropEffects.None; return; } base.OnDragDrop(de); } protected override void OnMouseHover() => _splitContainerDesigner?.SplitterPanelHover(); protected override void Dispose(bool disposing) { if (TryGetService(out IComponentChangeService? cs)) { cs.ComponentChanged -= OnComponentChanged; } base.Dispose(disposing); } public override void Initialize(IComponent component) { base.Initialize(component); _splitterPanel = (SplitterPanel)component; _designerHost = (IDesignerHost?)component.Site?.GetService(typeof(IDesignerHost)); _splitContainerDesigner = (SplitContainerDesigner?)_designerHost?.GetDesigner(_splitterPanel.Parent!); if (TryGetService(out IComponentChangeService? cs)) { cs.ComponentChanged += OnComponentChanged; } PropertyDescriptor? lockedProp = TypeDescriptor.GetProperties(component)["Locked"]; if (lockedProp is not null && _splitterPanel.Parent is SplitContainer) { lockedProp.SetValue(component, true); } } private void OnComponentChanged(object? sender, ComponentChangedEventArgs e) { if (_splitterPanel?.Parent is null) { return; } if (_splitterPanel.Controls.Count == 0) { using Graphics graphics = _splitterPanel.CreateGraphics(); DrawWaterMark(graphics); } else { // Erase WaterMark _splitterPanel.Invalidate(); } } internal void DrawSelectedBorder() { Control control = Control; // Black or white pen? Depends on the color of the control. Color penColor = control.BackColor.GetBrightness() < .5 ? ControlPaint.Light(control.BackColor) : ControlPaint.Dark(control.BackColor); using Pen pen = new(penColor) { DashStyle = DashStyle.Dash }; Rectangle rectangle = control.ClientRectangle; rectangle.Inflate(-4, -4); using Graphics graphics = control.CreateGraphics(); graphics.DrawRectangle(pen, rectangle); } internal void EraseBorder() { Control control = Control; Rectangle rectangle = control.ClientRectangle; rectangle.Inflate(-4, -4); using Pen pen = new(control.BackColor) { DashStyle = DashStyle.Dash }; using Graphics graphics = control.CreateGraphics(); graphics.DrawRectangle(pen, rectangle); control.Invalidate(); } internal void DrawWaterMark(Graphics g) { Control control = Control; Rectangle rectangle = control.ClientRectangle; string name = control.Name; Color waterMarkTextColor = Color.Black; var uis = GetService(typeof(IUIService)) as IUIService; if (uis?.Styles["SmartTagText"] is Color clr) { waterMarkTextColor = clr; } using Font drawFont = new("Arial", 8); int watermarkX = rectangle.Width / 2 - (int)g.MeasureString(name, drawFont).Width / 2; int watermarkY = rectangle.Height / 2; TextRenderer.DrawText(g, name, drawFont, new Point(watermarkX, watermarkY), waterMarkTextColor, TextFormatFlags.PreserveGraphicsClipping | TextFormatFlags.PreserveGraphicsTranslateTransform); } protected override void OnPaintAdornments(PaintEventArgs pe) { base.OnPaintAdornments(pe); if (_splitterPanel!.BorderStyle == BorderStyle.None) { DrawBorder(pe.Graphics); } if (Selected) { DrawSelectedBorder(); } if (_splitterPanel.Controls.Count == 0) { DrawWaterMark(pe.Graphics); } } /// <summary> /// Remove some basic properties that are not supported by the SplitterPanel. /// </summary> protected override void PreFilterProperties(IDictionary properties) { base.PreFilterProperties(properties); properties.Remove("Modifiers"); properties.Remove("Locked"); properties.Remove("GenerateMember"); // Remove the "(Name)" property from the property grid. foreach (DictionaryEntry de in properties) { PropertyDescriptor descriptor = (PropertyDescriptor)de.Value!; if (descriptor.Name.Equals("Name") && descriptor.DesignTimeOnly) { properties[de.Key] = TypeDescriptor.CreateProperty(descriptor.ComponentType, descriptor, BrowsableAttribute.No, DesignerSerializationVisibilityAttribute.Hidden); break; } } } /// <summary> /// Returns a list of SnapLine objects representing interesting alignment points for this control. /// These SnapLines are used to assist in the positioning of the control on a parent's surface. /// </summary> public override IList SnapLines { get { ArrayList? snapLines = null; // We only want PaddingSnaplines for SplitterPanels. AddPaddingSnapLines(ref snapLines); return snapLines; } } /// <summary> /// Retrieves a set of rules concerning the movement capabilities of a component. /// This should be one or more flags from the SelectionRules class. /// If no designer provides rules for a component, the component will not get any UI services. /// </summary> public override SelectionRules SelectionRules => Control.Parent is SplitContainer ? SelectionRules.Locked : SelectionRules.None; }