ErrorProvider.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ FX-1434 / FX-1434 / 1.0 / untmp / whidbey / REDBITS / ndp / fx / src / WinForms / Managed / System / WinForms / ErrorProvider.cs / 2 / ErrorProvider.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

namespace System.Windows.Forms { 
    using System.Threading; 
    using System.Runtime.Remoting;
    using System.Runtime.InteropServices; 
    using System.ComponentModel;
    using System.ComponentModel.Design;
    using System.Diagnostics;
    using System; 
    using System.Collections;
    using System.Globalization; 
    using System.Drawing; 
    using System.Windows.Forms;
    using System.Windows.Forms.Design; 
    using System.Windows.Forms.Internal;
    using System.Security.Permissions;

    ///  
    /// 
    ///     ErrorProvider presents a simple user interface for indicating to the 
    ///     user that a control on a form has an error associated with it.  If a 
    ///     error description string is specified for the control, then an icon
    ///     will appear next to the control, and when the mouse hovers over the 
    ///     icon, a tooltip will appear showing the error description string.
    /// 
    [
    ProvideProperty("IconPadding", typeof(Control)), 
    ProvideProperty("IconAlignment", typeof(Control)),
    ProvideProperty("Error", typeof(Control)), 
    ToolboxItemFilter("System.Windows.Forms"), 
    ComplexBindingProperties("DataSource", "DataMember"),
    SRDescription(SR.DescriptionErrorProvider) 
    ]
    public class ErrorProvider : Component, IExtenderProvider, ISupportInitialize {

        // 
        // FIELDS
        // 
 
        Hashtable items = new Hashtable();
        Hashtable windows = new Hashtable(); 
        Icon icon = DefaultIcon;
        IconRegion region;
        int itemIdCounter;
        int blinkRate; 
        ErrorBlinkStyle blinkStyle;
        bool showIcon = true;                       // used for blinking 
        private bool inSetErrorManager = false; 
        private bool setErrorManagerOnEndInit = false;
        private bool initializing = false; 
        [ThreadStatic]
        static Icon defaultIcon = null;
        const int defaultBlinkRate = 250;
        const ErrorBlinkStyle defaultBlinkStyle = ErrorBlinkStyle.BlinkIfDifferentError; 
        const ErrorIconAlignment defaultIconAlignment = ErrorIconAlignment.MiddleRight;
 
        // data binding 
        private ContainerControl parentControl;
        private object dataSource = null; 
        private string dataMember = null;
        private BindingManagerBase errorManager;
        private EventHandler currentChanged;
 
        // listen to the OnPropertyChanged event in the ContainerControl
        private EventHandler propChangedEvent; 
 
        private EventHandler onRightToLeftChanged;
        private bool rightToLeft = false; 

        private object userData;

        // 
        // CONSTRUCTOR
        // 
 
        /// 
        ///  
        ///     Default constructor.
        /// 
        public ErrorProvider() {
            icon = DefaultIcon; 
            blinkRate = defaultBlinkRate;
            blinkStyle = defaultBlinkStyle; 
            currentChanged = new EventHandler(ErrorManager_CurrentChanged); 
        }
 
        /// 
        /// 
        ///    [To be supplied.]
        ///  
        public ErrorProvider(ContainerControl parentControl) : this() {
            this.parentControl = parentControl; 
            propChangedEvent = new EventHandler(ParentControl_BindingContextChanged); 
            parentControl.BindingContextChanged += propChangedEvent;
        } 

        /// 
        /// 
        ///    [To be supplied.] 
        /// 
        public ErrorProvider(IContainer container) : this() { 
            container.Add(this); 
        }
 
        //
        // PROPERTIES
        //
 
        /// 
        public override ISite Site { 
            set { 
                base.Site = value;
                if (value == null) 
                    return;

                IDesignerHost host = value.GetService(typeof(IDesignerHost)) as IDesignerHost;
                if (host != null) { 
                    IComponent baseComp = host.RootComponent;
 
                    if (baseComp is ContainerControl) { 
                        this.ContainerControl = (ContainerControl) baseComp;
                    } 
                }
            }
        }
 
        /// 
        ///  
        ///     Returns or sets when the error icon flashes. 
        /// 
        [ 
        SRCategory(SR.CatBehavior),
        DefaultValue(defaultBlinkStyle),
        SRDescription(SR.ErrorProviderBlinkStyleDescr)
        ] 
        public ErrorBlinkStyle BlinkStyle {
            get { 
                if (blinkRate == 0) { 
                    return ErrorBlinkStyle.NeverBlink;
                } 
                return blinkStyle;
            }
            set {
                //valid values are 0x0 to 0x2 
                if (!ClientUtils.IsEnumValid(value, (int)value, (int)ErrorBlinkStyle.BlinkIfDifferentError, (int)ErrorBlinkStyle.NeverBlink)){
                    throw new InvalidEnumArgumentException("value", (int)value, typeof(ErrorBlinkStyle)); 
                } 

                // If the blinkRate == 0, then set blinkStyle = neverBlink 
                //
                if (this.blinkRate == 0) {
                    value = ErrorBlinkStyle.NeverBlink;
                } 

                if (this.blinkStyle == value) { 
                    return; 
                }
 
                if (value == ErrorBlinkStyle.AlwaysBlink) {
                    // we need to startBlinking on all the controlItems
                    // in our items hashTable.
                    this.showIcon = true; 
                    this.blinkStyle = ErrorBlinkStyle.AlwaysBlink;
                    foreach (ErrorWindow w in windows.Values) 
                    { 
                        w.StartBlinking();
                    } 
                }
                else if (blinkStyle == ErrorBlinkStyle.AlwaysBlink) {
                    // we need to stop blinking...
                    this.blinkStyle = value; 
                    foreach (ErrorWindow w in windows.Values) {
                        w.StopBlinking(); 
                    } 
                }
                else { 
                    this.blinkStyle = value;
                }
            }
        } 

        ///  
        ///  
        ///    Indicates what container control (usually the form) should be inspected for bindings.
        ///    A binding will reveal what control to place errors on for a 
        ///    error in the current row in the DataSource/DataMember pair.
        /// 
        [
        DefaultValue(null), 
        SRCategory(SR.CatData),
        SRDescription(SR.ErrorProviderContainerControlDescr) 
        ] 
        public ContainerControl ContainerControl {
            [UIPermission(SecurityAction.LinkDemand, Window=UIPermissionWindow.AllWindows)] 
            [UIPermission(SecurityAction.InheritanceDemand, Window=UIPermissionWindow.AllWindows)]
            get {
                return parentControl;
            } 
            set {
                if (parentControl != value) { 
                    if (parentControl != null) 
                        parentControl.BindingContextChanged -= propChangedEvent;
 
                    parentControl = value;

                    if (parentControl != null)
                        parentControl.BindingContextChanged += propChangedEvent; 

                    Set_ErrorManager(this.DataSource, this.DataMember, true); 
                } 
            }
        } 

        /// 
        /// 
        ///     This is used for international applications where the language 
        ///     is written from RightToLeft. When this property is true,
        //      text will be from right to left. 
        ///  
        [
        SRCategory(SR.CatAppearance), 
        Localizable(true),
        DefaultValue(false),
        SRDescription(SR.ControlRightToLeftDescr)
        ] 
        public virtual bool RightToLeft {
            get { 
 
                return rightToLeft;
            } 

            set {
                if (value != rightToLeft) {
                    rightToLeft = value; 
                    OnRightToLeftChanged(EventArgs.Empty);
                } 
            } 
        }
 
        /// 
        /// 
        ///    [To be supplied.]
        ///  
        [SRCategory(SR.CatPropertyChanged), SRDescription(SR.ControlOnRightToLeftChangedDescr)]
        public event EventHandler RightToLeftChanged { 
            add { 
                onRightToLeftChanged += value;
            } 
            remove {
                onRightToLeftChanged -= value;
            }
        } 

        ///  
        ///  
        ///    User defined data associated with the control.
        ///  
        [
        SRCategory(SR.CatData),
        Localizable(false),
        Bindable(true), 
        SRDescription(SR.ControlTagDescr),
        DefaultValue(null), 
        TypeConverter(typeof(StringConverter)), 
        ]
        public object Tag { 
            get {
                return userData;
            }
            set { 
                userData = value;
            } 
        } 

        private void Set_ErrorManager(object newDataSource, string newDataMember, bool force) { 
            if (inSetErrorManager)
                return;
            inSetErrorManager = true;
            try 
            {
                bool dataSourceChanged = this.DataSource != newDataSource; 
                bool dataMemberChanged = this.DataMember != newDataMember; 

                //if nothing changed, then do not do any work 
                //
                if (!dataSourceChanged && !dataMemberChanged && !force)
                {
                    return; 
                }
 
                // set the dataSource and the dataMember 
                //
                this.dataSource = newDataSource; 
                this.dataMember = newDataMember;

                if (initializing) {
                    setErrorManagerOnEndInit = true; 
                }
                else { 
                    // unwire the errorManager: 
                    //
                    UnwireEvents(errorManager); 

                    // get the new errorManager
                    //
                    if (parentControl != null && this.dataSource != null && parentControl.BindingContext != null) { 
                        errorManager = parentControl.BindingContext[this.dataSource, this.dataMember];
                    } 
                    else { 
                        errorManager = null;
                    } 

                    // wire the events
                    //
                    WireEvents(errorManager); 

                    // see if there are errors at the current 
                    // item in the list, w/o waiting for the position to change 
                    if (errorManager != null)
                        UpdateBinding(); 
                }
            } finally {
                inSetErrorManager = false;
            } 
        }
 
        ///  
        /// 
        ///    Indicates the source of data to bind errors against. 
        /// 
        [
        DefaultValue(null),
        SRCategory(SR.CatData), 
        AttributeProvider(typeof(IListSource)),
        SRDescription(SR.ErrorProviderDataSourceDescr) 
        ] 
        public object DataSource {
            get { 
                return dataSource;
            }
            set {
                if (parentControl != null && value != null && !String.IsNullOrEmpty(this.dataMember)) { 
                    // Let's check if the datamember exists in the new data source
                    try { 
                        errorManager = parentControl.BindingContext[value, this.dataMember]; 
                    }
                    catch (ArgumentException) { 
                        // The data member doesn't exist in the data source, so set it to null
                        this.dataMember = "";
                    }
                } 

                Set_ErrorManager(value, this.DataMember, false); 
            } 
        }
 
        /// 
        /// 
        ///    [To be supplied.]
        ///  
        private bool ShouldSerializeDataSource() {
            return (dataSource != null); 
        } 

        ///  
        /// 
        ///    Indicates the sub-list of data from the DataSource to bind errors against.
        /// 
        [ 
        DefaultValue(null),
        SRCategory(SR.CatData), 
        Editor("System.Windows.Forms.Design.DataMemberListEditor, " + AssemblyRef.SystemDesign, typeof(System.Drawing.Design.UITypeEditor)), 
        SRDescription(SR.ErrorProviderDataMemberDescr)
        ] 
        public string DataMember {
            get {
                return dataMember;
            } 
            set {
                if (value == null) value = ""; 
                Set_ErrorManager(this.DataSource, value, false); 
            }
        } 

        /// 
        /// 
        ///    [To be supplied.] 
        /// 
        private bool ShouldSerializeDataMember() { 
            return (dataMember != null && dataMember.Length != 0); 
        }
 
        /// 
        /// 
        ///    [To be supplied.]
        ///  
        public void BindToDataAndErrors(object newDataSource, string newDataMember) {
            Set_ErrorManager(newDataSource, newDataMember, false); 
        } 

        private void WireEvents(BindingManagerBase listManager) { 
            if (listManager != null) {
                listManager.CurrentChanged += currentChanged;
                listManager.BindingComplete += new BindingCompleteEventHandler(this.ErrorManager_BindingComplete);
 
                CurrencyManager currManager = listManager as CurrencyManager;
 
                if (currManager != null) { 
                    currManager.ItemChanged += new ItemChangedEventHandler(this.ErrorManager_ItemChanged);
                    currManager.Bindings.CollectionChanged += new CollectionChangeEventHandler(this.ErrorManager_BindingsChanged); 
                }
            }
        }
 
        private void UnwireEvents(BindingManagerBase listManager) {
            if (listManager != null) { 
                listManager.CurrentChanged -= currentChanged; 
                listManager.BindingComplete -= new BindingCompleteEventHandler(this.ErrorManager_BindingComplete);
 
                CurrencyManager currManager = listManager as CurrencyManager;

                if (currManager != null) {
                    currManager.ItemChanged -= new ItemChangedEventHandler(this.ErrorManager_ItemChanged); 
                    currManager.Bindings.CollectionChanged -= new CollectionChangeEventHandler(this.ErrorManager_BindingsChanged);
                } 
            } 
        }
 
        private void ErrorManager_BindingComplete(object sender, BindingCompleteEventArgs e) {
            Binding binding = e.Binding;

            if (binding != null && binding.Control != null) { 
                SetError(binding.Control, (e.ErrorText == null ? String.Empty : e.ErrorText));
            } 
        } 

        private void ErrorManager_BindingsChanged(object sender, CollectionChangeEventArgs e) { 
            ErrorManager_CurrentChanged(errorManager, e);
        }

        private void ParentControl_BindingContextChanged(object sender, EventArgs e) { 
            Set_ErrorManager(this.DataSource, this.DataMember, true);
        } 
 
        // Work around... we should figure out if errors changed automatically.
        ///  
        /// 
        ///    [To be supplied.]
        /// 
        public void UpdateBinding() { 
            ErrorManager_CurrentChanged(errorManager, EventArgs.Empty);
        } 
 
        private void ErrorManager_ItemChanged(object sender, ItemChangedEventArgs e) {
            BindingsCollection errBindings = errorManager.Bindings; 
            int bindingsCount = errBindings.Count;

            // If the list became empty then reset the errors
            if (e.Index == -1 && errorManager.Count == 0) { 
                for (int j = 0; j < bindingsCount; j++) {
                    if (errBindings[j].Control != null) { 
                        // ...ignore everything but bindings to Controls 
                        SetError(errBindings[j].Control, "");
                    } 
                }
            }
            else {
                ErrorManager_CurrentChanged(sender, e); 
            }
        } 
 
        private void ErrorManager_CurrentChanged(object sender, EventArgs e) {
            Debug.Assert(sender == errorManager, "who else can send us messages?"); 

            // flush the old list
            //
            // items.Clear(); 

            if (errorManager.Count == 0) { 
                return; 
            }
 
            object value = errorManager.Current;
            if ( !(value is IDataErrorInfo)) {
                return;
            } 

            BindingsCollection errBindings = errorManager.Bindings; 
            int bindingsCount = errBindings.Count; 

            // we need to delete the blinkPhases from each controlItem (suppose 
            // that the error that we get is the same error. then we want to
            // show the error and not blink )
            //
            foreach (ControlItem ctl in items.Values) { 
                ctl.BlinkPhase = 0;
            } 
 
            // We can only show one error per control, so we will build up a string...
            // 
            Hashtable controlError = new Hashtable(bindingsCount);

            for (int j = 0; j < bindingsCount; j++) {
 
                // Ignore everything but bindings to Controls
                if (errBindings[j].Control == null) { 
                    continue; 
                }
 
                BindToObject dataBinding = errBindings[j].BindToObject;
                string error = ((IDataErrorInfo) value)[dataBinding.BindingMemberInfo.BindingField];

                if (error == null) { 
                    error = "";
                } 
 
                string outputError = "";
 
                if (controlError.Contains(errBindings[j].Control))
                    outputError = (string) controlError[errBindings[j].Control];

                // VSWhidbey 106890: Utilize the error string without including the field name. 
                if (String.IsNullOrEmpty(outputError)) {
                    outputError = error; 
                } else { 
                    outputError = string.Concat(outputError, "\r\n", error);
                } 

                controlError[errBindings[j].Control] = outputError;
            }
 
            IEnumerator enumerator = controlError.GetEnumerator();
            while (enumerator.MoveNext()) { 
                DictionaryEntry entry = (DictionaryEntry) enumerator.Current; 
                SetError((Control) entry.Key, (string) entry.Value);
            } 
        }

        /// 
        ///  
        ///     Returns or set the rate in milliseconds at which the error icon flashes.
        ///  
        [ 
        SRCategory(SR.CatBehavior),
        DefaultValue(defaultBlinkRate), 
        SRDescription(SR.ErrorProviderBlinkRateDescr),
        RefreshProperties(RefreshProperties.Repaint)
        ]
        public int BlinkRate { 
            get {
                return blinkRate; 
            } 
            set {
                if (value < 0) { 
                    throw new ArgumentOutOfRangeException("BlinkRate", value, SR.GetString(SR.BlinkRateMustBeZeroOrMore));
                }
                blinkRate = value;
                // If we set the blinkRate = 0 then set BlinkStyle = NeverBlink 
                if (blinkRate == 0)
                    BlinkStyle = ErrorBlinkStyle.NeverBlink; 
            } 
        }
 
        /// 
        /// 
        ///     Demand load and cache the default icon.
        ///  
        /// 
        static Icon DefaultIcon { 
            get { 
                if (defaultIcon == null) {
                    lock (typeof(ErrorProvider)) { 
                        if (defaultIcon == null) {
                            defaultIcon = new Icon(typeof(ErrorProvider), "Error.ico");
                        }
                    } 
                }
                return defaultIcon; 
            } 
        }
 
        /// 
        /// 
        ///     Returns or sets the Icon that displayed next to a control when an error
        ///     description string has been set for the control.  For best results, an 
        ///     icon containing a 16 by 16 icon should be used.
        ///  
        [ 
        Localizable(true),
        SRCategory(SR.CatAppearance), 
        SRDescription(SR.ErrorProviderIconDescr)
        ]
        public Icon Icon {
            get { 
                return icon;
            } 
            set { 
                if (value == null)
                    throw new ArgumentNullException("value"); 
                icon = value;
                DisposeRegion();
                ErrorWindow[] array = new ErrorWindow[windows.Values.Count];
                windows.Values.CopyTo(array, 0); 
                for (int i = 0; i < array.Length; i++)
                    array[i].Update(false /*timerCaused*/); 
            } 
        }
 
        /// 
        /// 
        ///     Create the icon region on demand.
        ///  
        /// 
        internal IconRegion Region { 
            get { 
                if (region == null)
                    region = new IconRegion(Icon); 
                return region;
            }
        }
 
        //
        // METHODS 
        // 

        // Begin bulk member initialization - deferring binding to data source until EndInit is reached 
        void ISupportInitialize.BeginInit() {
            initializing = true;
        }
 
        // End bulk member initialization by binding to data source
        private void EndInitCore() { 
            initializing = false; 

            if (setErrorManagerOnEndInit) { 
                setErrorManagerOnEndInit = false;
                Set_ErrorManager(this.DataSource, this.DataMember, true);
            }
        } 

        // Check to see if DataSource has completed its initialization, before ending our initialization. 
        // If DataSource is still initializing, hook its Initialized event and wait for it to signal completion. 
        // If DataSource is already initialized, just go ahead and complete our initialization now.
        // 
        void ISupportInitialize.EndInit() {
            ISupportInitializeNotification dsInit = (this.DataSource as ISupportInitializeNotification);

            if (dsInit != null && !dsInit.IsInitialized) { 
                dsInit.Initialized += new EventHandler(DataSource_Initialized);
            } 
            else { 
                EndInitCore();
            } 
        }

        // Respond to late completion of the DataSource's initialization, by completing our own initialization.
        // This situation can arise if the call to the DataSource's EndInit() method comes after the call to the 
        // BindingSource's EndInit() method (since code-generated ordering of these calls is non-deterministic).
        // 
        private void DataSource_Initialized(object sender, EventArgs e) { 
            ISupportInitializeNotification dsInit = (this.DataSource as ISupportInitializeNotification);
 
            Debug.Assert(dsInit != null, "ErrorProvider: ISupportInitializeNotification.Initialized event received, but current DataSource does not support ISupportInitializeNotification!");
            Debug.Assert(dsInit.IsInitialized, "ErrorProvider: DataSource sent ISupportInitializeNotification.Initialized event but before it had finished initializing.");

            if (dsInit != null) { 
                dsInit.Initialized -= new EventHandler(DataSource_Initialized);
            } 
 
            EndInitCore();
        } 

        /// 
        /// 
        ///     Clears all errors being tracked by this error provider, ie. undoes all previous calls to SetError. 
        /// 
        public void Clear() { 
            ErrorWindow[] w = new ErrorWindow[windows.Values.Count]; 
            windows.Values.CopyTo(w, 0);
            for (int i = 0; i < w.Length; i++) { 
                w[i].Dispose();
            }
            windows.Clear();
            foreach (ControlItem item in items.Values) { 
                if (item != null) {
                    item.Dispose(); 
                } 
            }
            items.Clear(); 
        }

        /// 
        ///  
        ///     Returns whether a control can be extended.
        ///  
        public bool CanExtend(object extendee) { 
            return extendee is Control && !(extendee is Form) && !(extendee is ToolBar);
        } 

        /// 
        /// 
        ///     Release any resources that this component is using.  After calling Dispose, 
        ///     the component should no longer be used.
        ///  
        protected override void Dispose(bool disposing) { 
            if (disposing) {
                Clear(); 
                DisposeRegion();
                UnwireEvents(errorManager);
            }
            base.Dispose(disposing); 
        }
 
        ///  
        /// 
        ///     Helper to dispose the cached icon region. 
        /// 
        /// 
        void DisposeRegion() {
            if (region != null) { 
                region.Dispose();
                region = null; 
            } 
        }
 
        /// 
        /// 
        ///     Helper to make sure we have allocated a control item for this control.
        ///  
        /// 
        private ControlItem EnsureControlItem(Control control) { 
            if (control == null) 
                throw new ArgumentNullException("control");
            ControlItem item = (ControlItem)items[control]; 
            if (item == null) {
                item = new ControlItem(this, control, (IntPtr)(++itemIdCounter));
                items[control] = item;
            } 
            return item;
        } 
 
        /// 
        ///  
        ///     Helper to make sure we have allocated an error window for this control.
        /// 
        /// 
        internal ErrorWindow EnsureErrorWindow(Control parent) { 
            ErrorWindow window = (ErrorWindow)windows[parent];
            if (window == null) { 
                window = new ErrorWindow(this, parent); 
                windows[parent] = window;
            } 
            return window;
        }

        ///  
        /// 
        ///     Returns the current error description string for the specified control. 
        ///  
        [
        DefaultValue(""), 
        Localizable(true),
        SRCategory(SR.CatAppearance),
        SRDescription(SR.ErrorProviderErrorDescr)
        ] 
        public string GetError(Control control) {
            return EnsureControlItem(control).Error; 
        } 

        ///  
        /// 
        ///     Returns where the error icon should be placed relative to the control.
        /// 
        [ 
        DefaultValue(defaultIconAlignment),
        Localizable(true), 
        SRCategory(SR.CatAppearance), 
        SRDescription(SR.ErrorProviderIconAlignmentDescr)
        ] 
        public ErrorIconAlignment GetIconAlignment(Control control) {
            return EnsureControlItem(control).IconAlignment;
        }
 
        /// 
        ///  
        ///     Returns the amount of extra space to leave next to the error icon. 
        /// 
        [ 
        DefaultValue(0),
        Localizable(true),
        SRCategory(SR.CatAppearance),
        SRDescription(SR.ErrorProviderIconPaddingDescr) 
        ]
        public int GetIconPadding(Control control) { 
            return EnsureControlItem(control).IconPadding; 
        }
 
        private void ResetIcon() {
            Icon = DefaultIcon;
        }
 
        /// 
        ///  
        ///    [To be supplied.] 
        /// 
        [EditorBrowsable(EditorBrowsableState.Advanced)] 
        protected virtual void OnRightToLeftChanged(EventArgs e) {

            foreach (ErrorWindow w in windows.Values)
            { 
                w.Update(false);
            } 
 
            if (onRightToLeftChanged != null) {
                 onRightToLeftChanged(this, e); 
            }
        }

        ///  
        /// 
        ///     Sets the error description string for the specified control. 
        ///  
        public void SetError(Control control, string value) {
            EnsureControlItem(control).Error = value; 
        }

        /// 
        ///  
        ///     Sets where the error icon should be placed relative to the control.
        ///  
        public void SetIconAlignment(Control control, ErrorIconAlignment value) { 
            EnsureControlItem(control).IconAlignment = value;
        } 

        /// 
        /// 
        ///     Sets the amount of extra space to leave next to the error icon. 
        /// 
        public void SetIconPadding(Control control, int padding) { 
            EnsureControlItem(control).IconPadding = padding; 
        }
 
        private bool ShouldSerializeIcon() {
            return Icon != DefaultIcon;
        }
 
        /// 
        ///  
        ///     There is one ErrorWindow for each control parent.  It is parented to the 
        ///     control parent.  The window's region is made up of the regions from icons
        ///     of all child icons.  The window's size is the enclosing rectangle for all 
        ///     the regions.  A tooltip window is created as a child of this window.  The
        ///     rectangle associated with each error icon being displayed is added as a
        ///     tool to the tooltip window.
        ///  
        /// 
        internal class ErrorWindow : NativeWindow { 
 
            //
            // FIELDS 
            //

            ArrayList items = new ArrayList();
            Control parent; 
            ErrorProvider provider;
            Rectangle windowBounds = Rectangle.Empty; 
            System.Windows.Forms.Timer timer; 
            NativeWindow tipWindow;
 

            // VSWhidbey #455702
            DeviceContext mirrordc= null;
            Size mirrordcExtent = Size.Empty; 
            Point mirrordcOrigin = Point.Empty;
            DeviceContextMapMode mirrordcMode = DeviceContextMapMode.Text; 
 
            //
            // CONSTRUCTORS 
            //

            /// 
            ///  
            ///     Construct an error window for this provider and control parent.
            ///  
            public ErrorWindow(ErrorProvider provider, Control parent) { 
                this.provider = provider;
                this.parent = parent; 
            }

            //
            // METHODS 
            //
 
            ///  
            /// 
            ///     This is called when a control would like to show an error icon. 
            /// 
            public void Add(ControlItem item) {
                items.Add(item);
                if (!EnsureCreated()) 
                {
                    return; 
                } 

                NativeMethods.TOOLINFO_T toolInfo = new NativeMethods.TOOLINFO_T(); 
                toolInfo.cbSize = Marshal.SizeOf(toolInfo);
                toolInfo.hwnd = Handle;
                toolInfo.uId = item.Id;
                toolInfo.lpszText = item.Error; 
                toolInfo.uFlags = NativeMethods.TTF_SUBCLASS;
                UnsafeNativeMethods.SendMessage(new HandleRef(tipWindow, tipWindow.Handle), NativeMethods.TTM_ADDTOOL, 0, toolInfo); 
 
                Update(false /*timerCaused*/);
            } 

            /// 
            /// 
            ///     Called to get rid of any resources the Object may have. 
            /// 
            public void Dispose() { 
                EnsureDestroyed(); 
            }
 
            /// 
            /// 
            ///     Make sure the error window is created, and the tooltip window is created.
            ///  
            bool EnsureCreated() {
                if (Handle == IntPtr.Zero) { 
                    if (!parent.IsHandleCreated) 
                    {
                        return false; 
                    }
                    CreateParams cparams = new CreateParams();
                    cparams.Caption = String.Empty;
                    cparams.Style = NativeMethods.WS_VISIBLE | NativeMethods.WS_CHILD; 
                    cparams.ClassStyle = NativeMethods.CS_DBLCLKS;
                    cparams.X = 0; 
                    cparams.Y = 0; 
                    cparams.Width = 0;
                    cparams.Height = 0; 
                    cparams.Parent = parent.Handle;

                    CreateHandle(cparams);
 
                    NativeMethods.INITCOMMONCONTROLSEX icc = new NativeMethods.INITCOMMONCONTROLSEX();
                    icc.dwICC = NativeMethods.ICC_TAB_CLASSES; 
                    icc.dwSize = Marshal.SizeOf(icc); 
                    SafeNativeMethods.InitCommonControlsEx(icc);
                    cparams = new CreateParams(); 
                    cparams.Parent = Handle;
                    cparams.ClassName = NativeMethods.TOOLTIPS_CLASS;
                    cparams.Style = NativeMethods.TTS_ALWAYSTIP;
                    tipWindow = new NativeWindow(); 
                    tipWindow.CreateHandle(cparams);
 
                    UnsafeNativeMethods.SendMessage(new HandleRef(tipWindow, tipWindow.Handle), NativeMethods.TTM_SETMAXTIPWIDTH, 0, SystemInformation.MaxWindowTrackSize.Width); 
                    SafeNativeMethods.SetWindowPos(new HandleRef(tipWindow, tipWindow.Handle), NativeMethods.HWND_TOP, 0, 0, 0, 0, NativeMethods.SWP_NOSIZE | NativeMethods.SWP_NOMOVE | NativeMethods.SWP_NOACTIVATE);
                    UnsafeNativeMethods.SendMessage(new HandleRef(tipWindow, tipWindow.Handle), NativeMethods.TTM_SETDELAYTIME, NativeMethods.TTDT_INITIAL, 0); 
                }
                return true;
            }
 
            /// 
            ///  
            ///     Destroy the timer, toolwindow, and the error window itself. 
            /// 
            void EnsureDestroyed() { 
                if (timer != null) {
                    timer.Dispose();
                    timer = null;
                } 
                if (tipWindow != null) {
                    tipWindow.DestroyHandle(); 
                    tipWindow = null; 
                }
 
                // Hide the window and invalidate the parent to ensure
                // that we leave no visual artifacts... given that we
                // have a bizare region window, this is needed.
                // 
                SafeNativeMethods.SetWindowPos(new HandleRef(this, Handle),
                                               NativeMethods.HWND_TOP, 
                                               windowBounds.X, 
                                               windowBounds.Y,
                                               windowBounds.Width, 
                                               windowBounds.Height,
                                               NativeMethods.SWP_HIDEWINDOW
                                               | NativeMethods.SWP_NOSIZE
                                               | NativeMethods.SWP_NOMOVE); 
                if (parent != null) {
                    parent.Invalidate(true); 
                } 
                DestroyHandle();
 
                Debug.Assert(mirrordc == null, "Why is mirrordc non-null?");
                if (mirrordc != null) {
                    mirrordc.Dispose();
                } 
            }
 
            ///  
            ///
            /// VSWhidbey #455702. 
            ///
            /// Since we added mirroring to certain controls, we need to make sure the
            /// error icons show up in the correct place. We cannot mirror the errorwindow
            /// in EnsureCreated (although that would have been really easy), since we use 
            /// GDI+ for some of this code, and as we all know, GDI+ does not handle mirroring
            /// at all. 
            /// 
            /// To work around that we create our own mirrored dc when we need to.
            /// 
            /// 
            void CreateMirrorDC(IntPtr hdc, int originOffset) {

                Debug.Assert(mirrordc == null, "Why is mirrordc non-null? Did you not call RestoreMirrorDC?"); 

                mirrordc = DeviceContext.FromHdc(hdc); 
                if (parent.IsMirrored && mirrordc != null) { 
                    mirrordc.SaveHdc();
                    mirrordcExtent = mirrordc.ViewportExtent; 
                    mirrordcOrigin = mirrordc.ViewportOrigin;

                    mirrordcMode = mirrordc.SetMapMode(DeviceContextMapMode.Anisotropic);
                    mirrordc.ViewportExtent = new Size(-(mirrordcExtent.Width), mirrordcExtent.Height); 
                    mirrordc.ViewportOrigin = new Point(mirrordcOrigin.X + originOffset, mirrordcOrigin.Y);
                } 
            } 

            void RestoreMirrorDC() { 

                if (parent.IsMirrored && mirrordc != null) {
                    mirrordc.ViewportExtent = mirrordcExtent;
                    mirrordc.ViewportOrigin = mirrordcOrigin; 
                    mirrordc.SetMapMode(mirrordcMode);
                    mirrordc.RestoreHdc(); 
                    mirrordc.Dispose(); 
                }
 
                mirrordc= null;
                mirrordcExtent = Size.Empty;
                mirrordcOrigin = Point.Empty;
                mirrordcMode = DeviceContextMapMode.Text; 
            }
 
            ///  
            /// 
            ///     This is called when the error window needs to paint.  We paint each icon at its 
            ///     correct location.
            /// 
            void OnPaint(ref Message m) {
                NativeMethods.PAINTSTRUCT ps = new NativeMethods.PAINTSTRUCT(); 
                IntPtr hdc = UnsafeNativeMethods.BeginPaint(new HandleRef(this, Handle), ref ps);
 
                CreateMirrorDC(hdc, windowBounds.Width - 1); 

                try { 
                    for (int i = 0; i < items.Count; i++) {
                        ControlItem item = (ControlItem)items[i];
                        Rectangle bounds = item.GetIconBounds(provider.Region.Size);
                        SafeNativeMethods.DrawIconEx(new HandleRef(this, mirrordc.Hdc), bounds.X - windowBounds.X, bounds.Y - windowBounds.Y, new HandleRef(provider.Region, provider.Region.IconHandle), bounds.Width, bounds.Height, 0, NativeMethods.NullHandleRef, NativeMethods.DI_NORMAL); 
                    }
                } 
 
                finally {
                    RestoreMirrorDC(); 
                }

                UnsafeNativeMethods.EndPaint(new HandleRef(this, Handle), ref ps);
            } 

            protected override void OnThreadException(Exception e) { 
                Application.OnThreadException(e); 
            }
 
            /// 
            /// 
            ///     This is called when an error icon is flashing, and the view needs to be updatd.
            ///  
            void OnTimer(Object sender, EventArgs e) {
                int blinkPhase = 0; 
                for (int i = 0; i < items.Count; i++) { 
                    blinkPhase += ((ControlItem)items[i]).BlinkPhase;
                } 
                if (blinkPhase == 0 && provider.BlinkStyle != ErrorBlinkStyle.AlwaysBlink) {
                    Debug.Assert(timer != null);
                    timer.Stop();
                } 
                Update(true /*timerCaused*/);
            } 
 
            private void OnToolTipVisibilityChanging(System.IntPtr id, bool toolTipShown) {
                for (int i = 0; i < items.Count; i++) { 
                    if (((ControlItem)items[i]).Id == id) {
                        ((ControlItem)items[i]).ToolTipShown = toolTipShown;
                    }
                } 
#if DEBUG
                int shownTooltips = 0; 
                for (int j = 0; j < items.Count; j++) { 
                    if (((ControlItem)items[j]).ToolTipShown) {
                        shownTooltips++; 
                    }
                }
                Debug.Assert(shownTooltips <= 1);
#endif 
            }
 
            ///  
            /// 
            ///     This is called when a control no longer needs to display an error icon. 
            /// 
            public void Remove(ControlItem item) {
                items.Remove(item);
 
                if (tipWindow != null) {
                    NativeMethods.TOOLINFO_T toolInfo = new NativeMethods.TOOLINFO_T(); 
                    toolInfo.cbSize = Marshal.SizeOf(toolInfo); 
                    toolInfo.hwnd = Handle;
                    toolInfo.uId = item.Id; 
                    UnsafeNativeMethods.SendMessage(new HandleRef(tipWindow, tipWindow.Handle), NativeMethods.TTM_DELTOOL, 0, toolInfo);
                }

                if (items.Count == 0) { 
                    EnsureDestroyed();
                } 
                else { 
                    Update(false /*timerCaused*/);
                } 
            }

            /// 
            ///  
            ///     Start the blinking process.  The timer will fire until there are no more
            ///     icons that need to blink. 
            ///  
            internal void StartBlinking() {
                if (timer == null) { 
                    timer = new System.Windows.Forms.Timer();
                    timer.Tick += new EventHandler(OnTimer);
                }
                timer.Interval = provider.BlinkRate; 
                timer.Start();
                Update(false /*timerCaused*/); 
            } 

            internal void StopBlinking() { 
                if (timer != null) {
                    timer.Stop();
                }
                Update(false /*timerCaused*/); 
            }
 
            ///  
            /// 
            ///     Move and size the error window, compute and set the window region, 
            ///     set the tooltip rectangles and descriptions.  This basically brings
            ///     the error window up to date with the internal data structures.
            /// 
            public void Update(bool timerCaused) { 
                IconRegion iconRegion = provider.Region;
                Size size = iconRegion.Size; 
                windowBounds = Rectangle.Empty; 
                for (int i = 0; i < items.Count; i++) {
                    ControlItem item = (ControlItem)items[i]; 
                    Rectangle iconBounds = item.GetIconBounds(size);
                    if (windowBounds.IsEmpty)
                        windowBounds = iconBounds;
                    else 
                        windowBounds = Rectangle.Union(windowBounds, iconBounds);
                } 
 
                Region windowRegion =  new Region(new Rectangle(0, 0, 0, 0));
                IntPtr windowRegionHandle = IntPtr.Zero; 
                try {
                    for (int i = 0; i < items.Count; i++) {
                        ControlItem item = (ControlItem)items[i];
                        Rectangle iconBounds = item.GetIconBounds(size); 
                        iconBounds.X -= windowBounds.X;
                        iconBounds.Y -= windowBounds.Y; 
 
                        bool showIcon = true;
                        if (!item.ToolTipShown) { 
                            switch (provider.BlinkStyle) {
                                case ErrorBlinkStyle.NeverBlink:
                                    // always show icon
                                    break; 

                                case ErrorBlinkStyle.BlinkIfDifferentError: 
                                    showIcon = (item.BlinkPhase == 0) || (item.BlinkPhase > 0 && (item.BlinkPhase & 1) == (i & 1)); 
                                    break;
 
                                case ErrorBlinkStyle.AlwaysBlink:
                                    showIcon = ((i & 1) == 0) == provider.showIcon;
                                    break;
                            } 
                        }
 
                        if (showIcon) 
                        {
                            iconRegion.Region.Translate(iconBounds.X, iconBounds.Y); 
                            windowRegion.Union(iconRegion.Region);
                            iconRegion.Region.Translate(-iconBounds.X, -iconBounds.Y);
                        }
 
                        if (tipWindow != null) {
                            NativeMethods.TOOLINFO_T toolInfo = new NativeMethods.TOOLINFO_T(); 
                            toolInfo.cbSize = Marshal.SizeOf(toolInfo); 
                            toolInfo.hwnd = Handle;
                            toolInfo.uId = item.Id; 
                            toolInfo.lpszText = item.Error;
                            toolInfo.rect = NativeMethods.RECT.FromXYWH(iconBounds.X, iconBounds.Y, iconBounds.Width, iconBounds.Height);
                            toolInfo.uFlags = NativeMethods.TTF_SUBCLASS;
                            if (provider.RightToLeft) { 
                                toolInfo.uFlags |= NativeMethods.TTF_RTLREADING;
                            } 
                            UnsafeNativeMethods.SendMessage(new HandleRef(tipWindow, tipWindow.Handle), NativeMethods.TTM_SETTOOLINFO, 0, toolInfo); 
                        }
 
                        if (timerCaused && item.BlinkPhase > 0) {
                            item.BlinkPhase--;
                        }
                    } 
                    if (timerCaused) {
                        provider.showIcon = !provider.showIcon; 
                    } 

 
                    DeviceContext dc = null;
                    dc = DeviceContext.FromHwnd(this.Handle);
                    try {
                        CreateMirrorDC(dc.Hdc, windowBounds.Width); 

                        Graphics graphics = Graphics.FromHdcInternal(mirrordc.Hdc); 
                        try { 
                            windowRegionHandle = windowRegion.GetHrgn(graphics);
                            System.Internal.HandleCollector.Add(windowRegionHandle, NativeMethods.CommonHandles.GDI); 
                        }
                        finally {
                            graphics.Dispose();
                            RestoreMirrorDC(); 
                        }
 
                        if (UnsafeNativeMethods.SetWindowRgn(new HandleRef(this, Handle), new HandleRef(windowRegion, windowRegionHandle), true) != 0) { 
                            //The HWnd owns the region.
                            windowRegionHandle = IntPtr.Zero; 
                        }
                    }

                    finally { 
                        if (dc != null) {
                            dc.Dispose(); 
                        } 
                    }
 
                }
                finally {
                    windowRegion.Dispose();
                    if (windowRegionHandle != IntPtr.Zero) { 
                        SafeNativeMethods.DeleteObject(new HandleRef(null, windowRegionHandle));
                    } 
                } 

                SafeNativeMethods.SetWindowPos(new HandleRef(this, Handle), NativeMethods.HWND_TOP, windowBounds.X, windowBounds.Y, 
                                     windowBounds.Width, windowBounds.Height, NativeMethods.SWP_NOACTIVATE);
                SafeNativeMethods.InvalidateRect(new HandleRef(this, Handle), null, false);
            }
 
            /// 
            ///  
            ///     Called when the error window gets a windows message. 
            /// 
            protected override void WndProc(ref Message m) { 
                switch (m.Msg) {
                    case NativeMethods.WM_NOTIFY:
                        NativeMethods.NMHDR nmhdr = (NativeMethods.NMHDR)m.GetLParam(typeof(NativeMethods.NMHDR));
                        if (nmhdr.code == NativeMethods.TTN_SHOW || nmhdr.code == NativeMethods.TTN_POP) 
                        {
                            OnToolTipVisibilityChanging(nmhdr.idFrom, nmhdr.code == NativeMethods.TTN_SHOW); 
                        } 
                        break;
                    case NativeMethods.WM_ERASEBKGND: 
                        break;
                    case NativeMethods.WM_PAINT:
                        OnPaint(ref m);
                        break; 
                    default:
                        base.WndProc(ref m); 
                        break; 
                }
            } 
        }

        /// 
        ///  
        ///     There is one ControlItem for each control that the ErrorProvider is
        ///     is tracking state for.  It contains the values of all the extender 
        ///     properties. 
        /// 
        internal class ControlItem { 

            //
            // FIELDS
            // 

            string error; 
            Control control; 
            ErrorWindow window;
            ErrorProvider provider; 
            int blinkPhase;
            IntPtr id;
            int iconPadding;
            bool toolTipShown; 
            ErrorIconAlignment iconAlignment;
            const int startingBlinkPhase = 10;          // cause we want to blink 5 times 
 
            //
            // CONSTRUCTORS 
            //

            /// 
            ///  
            ///     Construct the item with its associated control, provider, and
            ///     a unique ID.  The ID is used for the tooltip ID. 
            ///  
            public ControlItem(ErrorProvider provider, Control control, IntPtr id) {
                this.toolTipShown = false; 
                this.iconAlignment = defaultIconAlignment;
                this.error = String.Empty;
                this.id = id;
                this.control = control; 
                this.provider = provider;
                this.control.HandleCreated += new EventHandler(OnCreateHandle); 
                this.control.HandleDestroyed += new EventHandler(OnDestroyHandle); 
                this.control.LocationChanged += new EventHandler(OnBoundsChanged);
                this.control.SizeChanged += new EventHandler(OnBoundsChanged); 
                this.control.VisibleChanged += new EventHandler(OnParentVisibleChanged);
                this.control.ParentChanged += new EventHandler(OnParentVisibleChanged);
            }
 
            public void Dispose() {
                if (control != null) { 
                    control.HandleCreated -= new EventHandler(OnCreateHandle); 
                    control.HandleDestroyed -= new EventHandler(OnDestroyHandle);
                    control.LocationChanged -= new EventHandler(OnBoundsChanged); 
                    control.SizeChanged -= new EventHandler(OnBoundsChanged);
                    control.VisibleChanged -= new EventHandler(OnParentVisibleChanged);
                    control.ParentChanged -= new EventHandler(OnParentVisibleChanged);
                } 
                error = string.Empty;
            } 
 
            //
            // PROPERTIES 
            //

            /// 
            ///  
            ///     Returns the unique ID for this control.  The ID used as the tooltip ID.
            ///  
            public IntPtr Id { 
                get {
                    return id; 
                }
            }

            ///  
            /// 
            ///     Returns or set the phase of blinking that this control is currently 
            ///     in.   If zero, the control is not blinking.  If odd, then the control 
            ///     is blinking, but invisible.  If even, the control is blinking and
            ///     currently visible.  Each time the blink timer fires, this value is 
            ///     reduced by one (until zero), thus causing the error icon to appear
            ///     or disappear.
            /// 
            public int BlinkPhase { 
                get {
                    return blinkPhase; 
                } 
                set {
                    blinkPhase = value; 
                }
            }

            ///  
            /// 
            ///     Returns or sets the icon padding for the control. 
            ///  
            public int IconPadding {
                get { 
                    return iconPadding;
                }
                set {
                    if (iconPadding != value) { 
                        iconPadding = value;
                        UpdateWindow(); 
                    } 
                }
            } 

            /// 
            /// 
            ///     Returns or sets the error description string for the control. 
            /// 
            public string Error { 
                get { 
                    return error;
                } 
                set {
                    if (value == null) {
                        value = "";
                    } 

                    // if the error is the same and the blinkStyle is not AlwaysBlink, then 
                    // we should not add the error and not start blinking. 
                    if (error.Equals(value) && provider.BlinkStyle != ErrorBlinkStyle.AlwaysBlink) {
                        return; 
                    }

                    bool adding = error.Length == 0;
                    error = value; 
                    if (value.Length == 0) {
                        RemoveFromWindow(); 
                    } 
                    else {
                        if (adding) { 
                            AddToWindow();
                        }
                        else {
                            if (provider.BlinkStyle != ErrorBlinkStyle.NeverBlink) { 
                                StartBlinking();
                            } 
                            else { 
                                UpdateWindow();
                            } 
                        }
                    }
                }
            } 

            ///  
            ///  
            ///     Returns or sets the location of the error icon for the control.
            ///  
            public ErrorIconAlignment IconAlignment {
                get {
                    return iconAlignment;
                } 
                set {
                    if (iconAlignment != value) { 
                        //valid values are 0x0 to 0x5 
                        if (!ClientUtils.IsEnumValid(value, (int)value, (int)ErrorIconAlignment.TopLeft, (int)ErrorIconAlignment.BottomRight))
                        { 
                            throw new InvalidEnumArgumentException("value", (int)value, typeof(ErrorIconAlignment));
                        }
                        iconAlignment = value;
                        UpdateWindow(); 
                    }
                } 
            } 

            ///  
            /// 
            ///     Returns true if the tooltip for this control item is currently shown.
            /// 
            public bool ToolTipShown 
            {
                get { 
                    return this.toolTipShown; 
                }
                set { 
                    this.toolTipShown = value;
                }
            }
 
            internal ErrorIconAlignment RTLTranslateIconAlignment(ErrorIconAlignment align) {
                if (provider.RightToLeft) { 
                    switch (align) { 
                        case ErrorIconAlignment.TopLeft:
                            return ErrorIconAlignment.TopRight; 
                        case ErrorIconAlignment.MiddleLeft:
                            return ErrorIconAlignment.MiddleRight;
                        case ErrorIconAlignment.BottomLeft:
                            return ErrorIconAlignment.BottomRight; 
                        case ErrorIconAlignment.TopRight:
                            return ErrorIconAlignment.TopLeft; 
                        case ErrorIconAlignment.MiddleRight: 
                            return ErrorIconAlignment.MiddleLeft;
                        case ErrorIconAlignment.BottomRight: 
                            return ErrorIconAlignment.BottomLeft;
                        default:
                            Debug.Fail("Unknown ErrorIconAlignment value");
                            return align; 
                    }
                } 
                else { 
                    return align;
                } 
            }

            /// 
            ///  
            ///     Returns the location of the icon in the same coordinate system as
            ///     the control being extended.  The size passed in is the size of 
            ///     the icon. 
            /// 
            internal Rectangle GetIconBounds(Size size) { 
                int x = 0;
                int y = 0;

                switch (RTLTranslateIconAlignment(IconAlignment)) { 
                    case ErrorIconAlignment.TopLeft:
                    case ErrorIconAlignment.MiddleLeft: 
                    case ErrorIconAlignment.BottomLeft: 
                        x = control.Left - size.Width - iconPadding;
                        break; 
                    case ErrorIconAlignment.TopRight:
                    case ErrorIconAlignment.MiddleRight:
                    case ErrorIconAlignment.BottomRight:
                        x = control.Right + iconPadding; 
                        break;
                } 
 
                switch (IconAlignment) {
                    case ErrorIconAlignment.TopLeft: 
                    case ErrorIconAlignment.TopRight:
                        y = control.Top;
                        break;
                    case ErrorIconAlignment.MiddleLeft: 
                    case ErrorIconAlignment.MiddleRight:
                        y = control.Top + (control.Height - size.Height) / 2; 
                        break; 
                    case ErrorIconAlignment.BottomLeft:
                    case ErrorIconAlignment.BottomRight: 
                        y = control.Bottom - size.Height;
                        break;
                }
 
                return new Rectangle(x, y, size.Width, size.Height);
            } 
 
            /// 
            ///  
            ///     If this control's error icon has been added to the error
            ///     window, then update the window state because some property
            ///     has changed.
            ///  
            void UpdateWindow() {
                if (window != null) { 
                    window.Update(false /*timerCaused*/); 
                }
            } 

            /// 
            /// 
            ///     If this control's error icon has been added to the error 
            ///     window, then start blinking the error window.  The blink
            ///     count 
            ///  
            void StartBlinking() {
                if (window != null) { 
                    BlinkPhase = startingBlinkPhase;
                    window.StartBlinking();
                }
            } 

            ///  
            ///  
            ///     Add this control's error icon to the error window.
            ///  
            void AddToWindow() {
                // if we are recreating the control, then add the control.
                if (window == null &&
                    (control.Created || control.RecreatingHandle) && 
                    control.Visible && control.ParentInternal != null &&
                    error.Length > 0) { 
                    window = provider.EnsureErrorWindow(control.ParentInternal); 
                    window.Add(this);
                    // Make sure that we blink if the style is set to AlwaysBlink or BlinkIfDifferrentError 
                    if (provider.BlinkStyle != ErrorBlinkStyle.NeverBlink)
                    {
                        StartBlinking();
                    } 
                }
            } 
 
            /// 
            ///  
            ///     Remove this control's error icon from the error window.
            /// 
            void RemoveFromWindow() {
                if (window != null) { 
                    window.Remove(this);
                    window = null; 
                } 
            }
 
            /// 
            /// 
            ///     This is called when a property on the control is changed.
            ///  
            void OnBoundsChanged(Object sender, EventArgs e) {
                UpdateWindow(); 
            } 

            void OnParentVisibleChanged(Object sender, EventArgs e) { 
                this.BlinkPhase = 0;
                RemoveFromWindow();
                AddToWindow();
            } 

            ///  
            ///  
            ///     This is called when the control's handle is created.
            ///  
            void OnCreateHandle(Object sender, EventArgs e) {
                AddToWindow();
            }
 
            /// 
            ///  
            ///     This is called when the control's handle is destroyed. 
            /// 
            void OnDestroyHandle(Object sender, EventArgs e) { 
                RemoveFromWindow();
            }
        }
 
        /// 
        ///  
        ///     This represents the HRGN of icon.  The region is calculate from the icon's mask. 
        /// 
        internal class IconRegion { 

            //
            // FIELDS
            // 

            Region region; 
            Icon icon; 

            // 
            // CONSTRUCTORS
            //

            ///  
            /// 
            ///     Constructor that takes an Icon and extracts its 16x16 version. 
            ///  
            public IconRegion(Icon icon) {
                this.icon = new Icon(icon, 16, 16); 
            }

            //
            // PROPERTIES 
            //
 
            ///  
            /// 
            ///     Returns the handle of the icon. 
            /// 
            public IntPtr IconHandle {
                get {
                    return icon.Handle; 
                }
            } 
 
            /// 
            ///  
            ///     Returns the handle of the region.
            /// 
            public Region Region {
                get { 
                    if (region == null) {
                        region = new Region(new Rectangle(0,0,0,0)); 
 
                        IntPtr mask = IntPtr.Zero;
                        try { 
                            Size size = icon.Size;
                            Bitmap bitmap = icon.ToBitmap();
                            bitmap.MakeTransparent();
                            mask = ControlPaint.CreateHBitmapTransparencyMask(bitmap); 
                            bitmap.Dispose();
 
                            int widthInBytes = size.Width / 8; 
                            byte[] bits = new byte[widthInBytes * size.Height];
                            SafeNativeMethods.GetBitmapBits(new HandleRef(null, mask), bits.Length, bits); 

                            for (int y = 0; y < size.Height; y++) {
                                for (int x = 0; x < size.Width; x++) {
                                    // see if bit is set in mask.  bits in byte are reversed. 0 is black (set). 
                                    if ((bits[y * widthInBytes + x / 8] & (1 << (7 - (x % 8)))) == 0) {
                                        region.Union(new Rectangle(x, y, 1, 1)); 
                                    } 
                                }
                            } 
                            region.Intersect(new Rectangle(0, 0, size.Width, size.Height));
                        }
                        finally {
                            if (mask != IntPtr.Zero) 
                                SafeNativeMethods.DeleteObject(new HandleRef(null, mask));
                        } 
                    } 

                    return region; 
                }
            }

            ///  
            /// 
            ///     Return the size of the icon. 
            ///  
            public Size Size {
                get { 
                    return icon.Size;
                }
            }
 
            //
            // METHODS 
            // 

            ///  
            /// 
            ///     Release any resources held by this Object.
            /// 
            public void Dispose() { 
                if (region != null) {
                    region.Dispose(); 
                    region = null; 
                }
                icon.Dispose(); 
            }

        }
    } 
}
 
 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK