File: winforms\Managed\System\WinForms\UserControl.cs
Project: ndp\fx\src\System.Windows.Forms.csproj (System.Windows.Forms)
//------------------------------------------------------------------------------
// <copyright file="UserControl.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------
 
/*
 */
namespace System.Windows.Forms {
 
    using Microsoft.Win32;
    using System;
    using System.ComponentModel;
    using System.ComponentModel.Design;
    using System.ComponentModel.Design.Serialization;
    using System.Diagnostics;
    using System.Drawing;    
    using System.Runtime.InteropServices;
    using System.Runtime.Remoting;
    using System.Security.Permissions;
    using System.Windows.Forms.Design;
    using System.Windows.Forms.Layout;
 
    /// <include file='doc\UserControl.uex' path='docs/doc[@for="UserControl"]/*' />
    /// <devdoc>
    ///     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.
    /// </devdoc>
    [
    ComVisible(true),
    ClassInterface(ClassInterfaceType.AutoDispatch),
    Designer("System.Windows.Forms.Design.UserControlDocumentDesigner, " + AssemblyRef.SystemDesign, typeof(IRootDesigner)),
    Designer("System.Windows.Forms.Design.ControlDesigner, " + AssemblyRef.SystemDesign),
    DesignerCategory("UserControl"),
    DefaultEvent("Load")
    ]
    public class UserControl : ContainerControl {
        private static readonly object EVENT_LOAD = new object();
        private BorderStyle borderStyle = System.Windows.Forms.BorderStyle.None;
 
        /// <include file='doc\UserControl.uex' path='docs/doc[@for="UserControl.UserControl"]/*' />
        /// <devdoc>
        ///    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.
        /// </devdoc>
        public UserControl() {
            SetScrollState(ScrollStateAutoScrolling, false);
            SetState(STATE_VISIBLE, true);
            SetState(STATE_TOPLEVEL, false);
	    SetStyle(ControlStyles.SupportsTransparentBackColor, true);
        }
        
        /// <devdoc>
        ///    <para> Override to re-expose AutoSize.</para>
        /// </devdoc>
        [Browsable(true), EditorBrowsable(EditorBrowsableState.Always),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public override bool AutoSize
        {
            get
            {
                return base.AutoSize;
            }
            set
            {
                base.AutoSize = value;
            }
        }
 
        /// <devdoc>
        ///    <para> Re-expose AutoSizeChanged.</para>
        /// </devdoc>
        [Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
        public new event EventHandler AutoSizeChanged {
            add {
                base.AutoSizeChanged += value;
            }
            remove {
                base.AutoSizeChanged -= value;
            }
        }
 
        /// <devdoc>
        ///     Allows the control to optionally shrink when AutoSize is true.
        /// </devdoc>
        [
        SRDescription(SR.ControlAutoSizeModeDescr),
        SRCategory(SR.CatLayout),
        Browsable(true),
        DefaultValue(AutoSizeMode.GrowOnly),
        Localizable(true)
        ]
        public AutoSizeMode AutoSizeMode {
            get {
                return GetAutoSizeMode();
            }
            set {
                if (!ClientUtils.IsEnumValid(value, (int)value, (int)AutoSizeMode.GrowAndShrink, (int)AutoSizeMode.GrowOnly))
                {
                    throw new InvalidEnumArgumentException("value", (int)value, typeof(AutoSizeMode));
                }
                
                if (GetAutoSizeMode() != value) {                    
                    SetAutoSizeMode(value);
                    Control toLayout = DesignMode || ParentInternal == null ? this : ParentInternal;
                    
                    if(toLayout != 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);
                    }
                }
            }
        }
 
        /// <include file='doc\UserControl.uex' path='docs/doc[@for="UserControl.AutoValidate"]/*' />
        /// <devdoc>
        ///     Indicates whether controls in this container will be automatically validated when the focus changes.
        /// </devdoc>
        [
        Browsable(true),
        EditorBrowsable(EditorBrowsableState.Always),
        ]
        public override AutoValidate AutoValidate {
            get {
                return base.AutoValidate;
            }
            set {
                base.AutoValidate = value;
            }
        }
 
        /// <include file='doc\UserControl.uex' path='docs/doc[@for="UserControl.AutoValidateChanged"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [
        Browsable(true),
        EditorBrowsable(EditorBrowsableState.Always),
        ]
        public new event EventHandler AutoValidateChanged {
            add {
                base.AutoValidateChanged += value;
            }
            remove {
                base.AutoValidateChanged -= value;
            }
        }
 
		/// <include file='doc\UserControl.uex' path='docs/doc[@for="UserControl.BorderStyle"]/*' />
        /// <devdoc>
        ///    <para> 
        ///       Indicates the borderstyle for the UserControl.
        ///    </para>
        /// </devdoc>
        [
        SRCategory(SR.CatAppearance),
        DefaultValue(BorderStyle.None),
        SRDescription(SR.UserControlBorderStyleDescr),
        Browsable(true), EditorBrowsable(EditorBrowsableState.Always)
        ]
        public BorderStyle BorderStyle {
            get {
                return borderStyle;
            }
 
            set {
                if (borderStyle != value) {
                    //valid values are 0x0 to 0x2
                    if (!ClientUtils.IsEnumValid(value, (int)value, (int)BorderStyle.None, (int)BorderStyle.Fixed3D))
                    {
                        throw new InvalidEnumArgumentException("value", (int)value, typeof(BorderStyle));
                    }
 
                    borderStyle = value;
                    UpdateStyles();
                }
            }
        }
 
        /// <include file='doc\UserControl.uex' path='docs/doc[@for="UserControl.CreateParams"]/*' />
        /// <internalonly/>
        /// <devdoc>
        ///    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.
        /// </devdoc>
        protected override CreateParams CreateParams {
            [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
            get {
                CreateParams cp = base.CreateParams;
                cp.ExStyle |= NativeMethods.WS_EX_CONTROLPARENT;
 
                cp.ExStyle &= (~NativeMethods.WS_EX_CLIENTEDGE);
                cp.Style &= (~NativeMethods.WS_BORDER);
 
                switch (borderStyle) {
                    case BorderStyle.Fixed3D:
                        cp.ExStyle |= NativeMethods.WS_EX_CLIENTEDGE;
                        break;
                    case BorderStyle.FixedSingle:
                        cp.Style |= NativeMethods.WS_BORDER;
                        break;
                }
                return cp;
            }
        }
        
        /// <include file='doc\UserControl.uex' path='docs/doc[@for="UserControl.DefaultSize"]/*' />
        /// <devdoc>
        ///     The default size for this user control.
        /// </devdoc>
        protected override Size DefaultSize {
            get {
                return new Size(150, 150);
            }
        }
 
        /// <include file='doc\UserControl.uex' path='docs/doc[@for="UserControl.Load"]/*' />
        /// <devdoc>
        ///    <para>Occurs before the control becomes visible.</para>
        /// </devdoc>
        [SRCategory(SR.CatBehavior), SRDescription(SR.UserControlOnLoadDescr)]
        public event EventHandler Load {
            add {
                Events.AddHandler(EVENT_LOAD, value);
            }
            remove {
                Events.RemoveHandler(EVENT_LOAD, value);
            }
        }
 
        /// <include file='doc\UserControl.uex' path='docs/doc[@for="UserControl.Text"]/*' />
        [
        Browsable(false), EditorBrowsable(EditorBrowsableState.Never), 
        Bindable(false), 
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ]                
        public override string Text {
            get {
                return base.Text;
            }
            set {
                base.Text = value;
            }
        }
 
        /// <include file='doc\UserControl.uex' path='docs/doc[@for="UserControl.TextChanged"]/*' />
        /// <internalonly/>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler TextChanged {
            add {
                base.TextChanged += value;
            }
            remove {
                base.TextChanged -= value;
            }
        }
        
        /// <include file='doc\UserControl.uex' path='docs/doc[@for="UserControl.ValidateChildren"]/*' />
        /// <devdoc>
        ///     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.
        /// </devdoc>
        [Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
        public override bool ValidateChildren() {
            return base.ValidateChildren();
        }
 
        /// <include file='doc\UserControl.uex' path='docs/doc[@for="UserControl.ValidateChildren1"]/*' />
        /// <devdoc>
        ///     Validates all the child controls in the container. Exactly which controls are
        ///     validated and which controls are skipped is determined by <paramref name="flags"/>.
        /// </devdoc>
        [Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
        public override bool ValidateChildren(ValidationConstraints validationConstraints) {
            return base.ValidateChildren(validationConstraints);
        }
 
        private bool FocusInside() {
            if (!IsHandleCreated) return false;
 
            IntPtr hwndFocus = UnsafeNativeMethods.GetFocus();
            if (hwndFocus == IntPtr.Zero) return false;
 
            IntPtr hwnd = Handle;
            if (hwnd == hwndFocus || SafeNativeMethods.IsChild(new HandleRef(this, hwnd), new HandleRef(null, hwndFocus)))
                return true;
 
            return false;
        }
 
        /// <include file='doc\UserControl.uex' path='docs/doc[@for="UserControl.OnCreateControl"]/*' />
        /// <devdoc>
        ///    <para> Raises the CreateControl event.</para>
        /// </devdoc>
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        protected override void OnCreateControl() {
            base.OnCreateControl();
            
            OnLoad(EventArgs.Empty);
        }
 
        /// <include file='doc\UserControl.uex' path='docs/doc[@for="UserControl.OnLoad"]/*' />
        /// <devdoc>
        ///    <para>The Load event is fired before the control becomes visible for the first time.</para>
        /// </devdoc>
        [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 handler = (EventHandler)Events[EVENT_LOAD];
            if (handler != null) handler(this,e);
        }
 
        /// <include file='doc\UserControl.uex' path='docs/doc[@for="UserControl.OnResize"]/*' />
        /// <devdoc>
        ///     OnResize override to invalidate entire control in Stetch mode
        /// </devdoc>
        /// <internalonly/>
        protected override void OnResize(EventArgs e) {
            base.OnResize(e);
            if (BackgroundImage != null) {
                Invalidate();
            }
        }
 
        /// <include file='doc\UserControl.uex' path='docs/doc[@for="UserControl.OnMouseDown"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        protected override void OnMouseDown(MouseEventArgs e) {
            if (!FocusInside())
                FocusInternal();
            base.OnMouseDown(e);
        }
 
        private void WmSetFocus(ref Message m) {
            if (!HostedInWin32DialogManager) {
                IntSecurity.ModifyFocus.Assert();
                try {
                    if (ActiveControl == null)
                        SelectNextControl(null, true, true, true, false);
                }
                finally {
                    System.Security.CodeAccessPermission.RevertAssert();
                }
            }
            if (!ValidationCancelled) {
                base.WndProc(ref m);
            }
            
        }
 
        /// <include file='doc\UserControl.uex' path='docs/doc[@for="UserControl.WndProc"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        protected override void WndProc(ref Message m) {
            switch (m.Msg) {
                case NativeMethods.WM_SETFOCUS:
                    WmSetFocus(ref m);
                    break;
                default:
                    base.WndProc(ref m);
                    break;
            }
        }
    }
}