| File: System\Windows\Forms\UserControl.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.ComponentModel.Design; using System.Drawing; using System.Windows.Forms.Layout; namespace System.Windows.Forms; /// <summary> /// Represents an empty control that can be used in the Forms Designer to create other controls. By extending form, /// UserControl inherits all of the standard positioning and mnemonic handling code that is necessary in a user control. /// </summary> [Designer($"System.Windows.Forms.Design.UserControlDocumentDesigner, {Assemblies.SystemDesign}", typeof(IRootDesigner))] [Designer($"System.Windows.Forms.Design.ControlDesigner, {Assemblies.SystemDesign}")] [DesignerCategory("UserControl")] [DefaultEvent(nameof(Load))] public class UserControl : ContainerControl { private static readonly object s_loadEvent = new(); private BorderStyle _borderStyle = BorderStyle.None; /// <summary> /// Creates a new UserControl object. A vast majority of people /// will not want to instantiate this class directly, but will be a /// sub-class of it. /// </summary> public UserControl() { SetScrollState(ScrollStateAutoScrolling, false); SetState(States.Visible, true); SetState(States.TopLevel, false); SetStyle(ControlStyles.SupportsTransparentBackColor, true); } /// <summary> /// Override to re-expose AutoSize. /// </summary> [Browsable(true)] [EditorBrowsable(EditorBrowsableState.Always)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public override bool AutoSize { get => base.AutoSize; set => base.AutoSize = value; } /// <summary> /// Re-expose AutoSizeChanged. /// </summary> [Browsable(true)] [EditorBrowsable(EditorBrowsableState.Always)] public new event EventHandler? AutoSizeChanged { add => base.AutoSizeChanged += value; remove => base.AutoSizeChanged -= value; } /// <summary> /// Allows the control to optionally shrink when AutoSize is true. /// </summary> [SRDescription(nameof(SR.ControlAutoSizeModeDescr))] [SRCategory(nameof(SR.CatLayout))] [Browsable(true)] [DefaultValue(AutoSizeMode.GrowOnly)] [Localizable(true)] public AutoSizeMode AutoSizeMode { get { return GetAutoSizeMode(); } set { SourceGenerated.EnumValidator.Validate(value); if (GetAutoSizeMode() != value) { SetAutoSizeMode(value); Control toLayout = DesignMode || ParentInternal is null ? this : ParentInternal; if (toLayout is not null) { // DefaultLayout does not keep anchor information until it needs to. When // AutoSize became a common property, we could no longer blindly call into // DefaultLayout, so now we do a special InitLayout just for DefaultLayout. if (toLayout.LayoutEngine == DefaultLayout.Instance) { toLayout.LayoutEngine.InitLayout(this, BoundsSpecified.Size); } LayoutTransaction.DoLayout(toLayout, this, PropertyNames.AutoSize); } } } } /// <summary> /// Indicates whether controls in this container will be automatically validated when the focus changes. /// </summary> [Browsable(true)] [EditorBrowsable(EditorBrowsableState.Always)] public override AutoValidate AutoValidate { get => base.AutoValidate; set => base.AutoValidate = value; } [Browsable(true)] [EditorBrowsable(EditorBrowsableState.Always)] public new event EventHandler? AutoValidateChanged { add => base.AutoValidateChanged += value; remove => base.AutoValidateChanged -= value; } /// <summary> /// /// Indicates the borderstyle for the UserControl. /// </summary> [SRCategory(nameof(SR.CatAppearance))] [DefaultValue(BorderStyle.None)] [SRDescription(nameof(SR.UserControlBorderStyleDescr))] [Browsable(true)] [EditorBrowsable(EditorBrowsableState.Always)] public BorderStyle BorderStyle { get { return _borderStyle; } set { if (_borderStyle != value) { // valid values are 0x0 to 0x2 SourceGenerated.EnumValidator.Validate(value); _borderStyle = value; UpdateStyles(); } } } /// <summary> /// Returns the parameters needed to create the handle. Inheriting classes /// can override this to provide extra functionality. They should not, /// however, forget to call base.getCreateParams() first to get the struct /// filled up with the basic info.This is required as we now need to pass the /// styles for appropriate BorderStyle that is set by the user. /// </summary> protected override CreateParams CreateParams { get { CreateParams cp = base.CreateParams; cp.Style &= ~(int)WINDOW_STYLE.WS_BORDER; cp.ExStyle |= (int)WINDOW_EX_STYLE.WS_EX_CONTROLPARENT; cp.ExStyle &= ~(int)WINDOW_EX_STYLE.WS_EX_CLIENTEDGE; switch (_borderStyle) { case BorderStyle.Fixed3D: cp.ExStyle |= (int)WINDOW_EX_STYLE.WS_EX_CLIENTEDGE; break; case BorderStyle.FixedSingle: cp.Style |= (int)WINDOW_STYLE.WS_BORDER; break; } return cp; } } /// <summary> /// The default size for this user control. /// </summary> protected override Size DefaultSize { get { return new Size(150, 150); } } /// <summary> /// Occurs before the control becomes visible. /// </summary> [SRCategory(nameof(SR.CatBehavior))] [SRDescription(nameof(SR.UserControlOnLoadDescr))] public event EventHandler? Load { add => Events.AddHandler(s_loadEvent, value); remove => Events.RemoveHandler(s_loadEvent, value); } [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Never)] [Bindable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [AllowNull] public override string Text { get => base.Text; set => base.Text = value; } [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Never)] public new event EventHandler? TextChanged { add => base.TextChanged += value; remove => base.TextChanged -= value; } /// <summary> /// Validates all selectable child controls in the container, including descendants. This is /// equivalent to calling ValidateChildren(ValidationConstraints.Selectable). See <see cref="ValidationConstraints.Selectable"/> /// for details of exactly which child controls will be validated. /// </summary> [Browsable(true)] [EditorBrowsable(EditorBrowsableState.Always)] public override bool ValidateChildren() { return base.ValidateChildren(); } /// <summary> /// Validates all the child controls in the container. Exactly which controls are /// validated and which controls are skipped is determined by <paramref name="validationConstraints"/>. /// </summary> [Browsable(true)] [EditorBrowsable(EditorBrowsableState.Always)] public override bool ValidateChildren(ValidationConstraints validationConstraints) { return base.ValidateChildren(validationConstraints); } private bool FocusInside() { if (!IsHandleCreated) { return false; } HWND hwndFocus = PInvoke.GetFocus(); if (hwndFocus.IsNull) { return false; } return HWND == hwndFocus || PInvoke.IsChild(this, hwndFocus); } /// <summary> /// Raises the CreateControl event. /// </summary> [EditorBrowsable(EditorBrowsableState.Advanced)] protected override void OnCreateControl() { base.OnCreateControl(); OnLoad(EventArgs.Empty); } /// <summary> /// The Load event is fired before the control becomes visible for the first time. /// </summary> [EditorBrowsable(EditorBrowsableState.Advanced)] protected virtual void OnLoad(EventArgs e) { // There is no good way to explain this event except to say // that it's just another name for OnControlCreated. ((EventHandler?)Events[s_loadEvent])?.Invoke(this, e); } /// <summary> /// OnResize override to invalidate entire control in Stetch mode /// </summary> protected override void OnResize(EventArgs e) { base.OnResize(e); if (BackgroundImage is not null) { Invalidate(); } } [EditorBrowsable(EditorBrowsableState.Advanced)] protected override void OnMouseDown(MouseEventArgs e) { if (!FocusInside()) { Focus(); } base.OnMouseDown(e); } private void WmSetFocus(ref Message m) { if (!HostedInWin32DialogManager) { if (ActiveControl is null) { SelectNextControl(null, true, true, true, false); } } if (!ValidationCancelled) { base.WndProc(ref m); } } [EditorBrowsable(EditorBrowsableState.Advanced)] protected override void WndProc(ref Message m) { switch (m.MsgInternal) { case PInvokeCore.WM_SETFOCUS: WmSetFocus(ref m); break; default: base.WndProc(ref m); break; } } }