diff --git a/src/System.Windows.Forms/src/Resources/SR.resx b/src/System.Windows.Forms/src/Resources/SR.resx index 8de7a251221..8e999923c63 100644 --- a/src/System.Windows.Forms/src/Resources/SR.resx +++ b/src/System.Windows.Forms/src/Resources/SR.resx @@ -5753,10 +5753,10 @@ Stack trace where the illegal operation occurred was: Occurs when a tab page is being selected. - + TabPage cannot be added to a '{0}'. TabPages can only be added to TabControls. - + TabPage cannot be added to another TabPage. TabPages can only be added to TabControls. diff --git a/src/System.Windows.Forms/src/Resources/xlf/SR.cs.xlf b/src/System.Windows.Forms/src/Resources/xlf/SR.cs.xlf index 4376647a1a4..25ce1f9aa3d 100644 --- a/src/System.Windows.Forms/src/Resources/xlf/SR.cs.xlf +++ b/src/System.Windows.Forms/src/Resources/xlf/SR.cs.xlf @@ -9511,12 +9511,12 @@ Trasování zásobníku, kde došlo k neplatné operaci: Funkce není v tomto operačním systému podporována. - + TabPage cannot be added to a '{0}'. TabPages can only be added to TabControls. Objekt TabPage nelze přidat k objektu {0}. Objekt TabPages lze přidat pouze k ovládacímu prvku TabControls. - + TabPage cannot be added to another TabPage. TabPages can only be added to TabControls. Objekt TabPage nelze přidat k jinému ovládacímu prvku TabPage. Objekt TabPages lze přidat pouze k ovládacímu prvku TabControls. diff --git a/src/System.Windows.Forms/src/Resources/xlf/SR.de.xlf b/src/System.Windows.Forms/src/Resources/xlf/SR.de.xlf index bf0fa495ecf..0bcc5289381 100644 --- a/src/System.Windows.Forms/src/Resources/xlf/SR.de.xlf +++ b/src/System.Windows.Forms/src/Resources/xlf/SR.de.xlf @@ -9511,12 +9511,12 @@ Stapelüberwachung, in der der unzulässige Vorgang auftrat: Das Feature wird bei diesem Betriebssystem nicht unterstützt. - + TabPage cannot be added to a '{0}'. TabPages can only be added to TabControls. TabPage kann nicht zu einem {0} hinzugefügt werden. TabPages können nur zu TabControls hinzugefügt werden. - + TabPage cannot be added to another TabPage. TabPages can only be added to TabControls. TabPage kann nicht zu einer anderen TabPage hinzugefügt werden. TabPages können nur zu TabControls hinzugefügt werden. diff --git a/src/System.Windows.Forms/src/Resources/xlf/SR.es.xlf b/src/System.Windows.Forms/src/Resources/xlf/SR.es.xlf index 59b79adc3d9..e12178da10a 100644 --- a/src/System.Windows.Forms/src/Resources/xlf/SR.es.xlf +++ b/src/System.Windows.Forms/src/Resources/xlf/SR.es.xlf @@ -9511,12 +9511,12 @@ El seguimiento de la pila donde tuvo lugar la operación no válida fue: Este sistema operativo no admite esta característica. - + TabPage cannot be added to a '{0}'. TabPages can only be added to TabControls. No se puede agregar TabPage a '{0}'. Sólo se pueden agregar TabPages a TabControls. - + TabPage cannot be added to another TabPage. TabPages can only be added to TabControls. No se puede agregar una TabPage a otra TabPage. Sólo se pueden agregar TabPages a TabControls. diff --git a/src/System.Windows.Forms/src/Resources/xlf/SR.fr.xlf b/src/System.Windows.Forms/src/Resources/xlf/SR.fr.xlf index 166cefef57d..d11cd0eef3f 100644 --- a/src/System.Windows.Forms/src/Resources/xlf/SR.fr.xlf +++ b/src/System.Windows.Forms/src/Resources/xlf/SR.fr.xlf @@ -9511,12 +9511,12 @@ Cette opération non conforme s'est produite sur la trace de la pile : Fonctionnalité non prise en charge par ce système d'exploitation. - + TabPage cannot be added to a '{0}'. TabPages can only be added to TabControls. Un TabPage ne peut pas être ajouté à un '{0}'. Les TabPages ne peuvent être ajoutés qu'aux TabControls. - + TabPage cannot be added to another TabPage. TabPages can only be added to TabControls. Un TabPage ne peut pas être ajouté à un autre TabPage. Les TabPages ne peuvent être ajoutés qu'aux TabControls. diff --git a/src/System.Windows.Forms/src/Resources/xlf/SR.it.xlf b/src/System.Windows.Forms/src/Resources/xlf/SR.it.xlf index fdec11eb0a7..594155f5b85 100644 --- a/src/System.Windows.Forms/src/Resources/xlf/SR.it.xlf +++ b/src/System.Windows.Forms/src/Resources/xlf/SR.it.xlf @@ -9511,12 +9511,12 @@ Traccia dello stack da cui si è verificata l'operazione non valida: Funzionalità non supportata in questo sistema operativo. - + TabPage cannot be added to a '{0}'. TabPages can only be added to TabControls. Impossibile aggiungere un oggetto TabPage a '{0}'. Gli oggetti TabPage possono essere aggiunti solo a una classe TabControl. - + TabPage cannot be added to another TabPage. TabPages can only be added to TabControls. Impossibile aggiungere un oggetto TabPage a un altro oggetto TabPage. Gli oggetti TabPage possono essere aggiunti solo a una classe TabControl. diff --git a/src/System.Windows.Forms/src/Resources/xlf/SR.ja.xlf b/src/System.Windows.Forms/src/Resources/xlf/SR.ja.xlf index 49b7e7c84ae..0425b468e01 100644 --- a/src/System.Windows.Forms/src/Resources/xlf/SR.ja.xlf +++ b/src/System.Windows.Forms/src/Resources/xlf/SR.ja.xlf @@ -9511,12 +9511,12 @@ Stack trace where the illegal operation occurred was: 機能はこのオペレーティング システムでサポートされていません。 - + TabPage cannot be added to a '{0}'. TabPages can only be added to TabControls. TabPage を '{0}' に追加できません。 TabPages は TabControls にのみ追加できます。 - + TabPage cannot be added to another TabPage. TabPages can only be added to TabControls. TabPage を他の TabPage に追加できません。 TabPages は、TabControls にのみ追加できます。 diff --git a/src/System.Windows.Forms/src/Resources/xlf/SR.ko.xlf b/src/System.Windows.Forms/src/Resources/xlf/SR.ko.xlf index c16c90d0b7d..5500bfcbed7 100644 --- a/src/System.Windows.Forms/src/Resources/xlf/SR.ko.xlf +++ b/src/System.Windows.Forms/src/Resources/xlf/SR.ko.xlf @@ -9511,12 +9511,12 @@ Stack trace where the illegal operation occurred was: 이 운영 시스템에서 지원되지 않는 기능입니다. - + TabPage cannot be added to a '{0}'. TabPages can only be added to TabControls. TabPage를 '{0}'에 추가할 수 없습니다. TabPages는 TabControls에만 추가할 수 있습니다. - + TabPage cannot be added to another TabPage. TabPages can only be added to TabControls. TabPage를 다른 TabPage에 추가할 수 없습니다. TabPages는 TabControls에만 추가할 수 있습니다. diff --git a/src/System.Windows.Forms/src/Resources/xlf/SR.pl.xlf b/src/System.Windows.Forms/src/Resources/xlf/SR.pl.xlf index 63d1708b860..06d1eacd828 100644 --- a/src/System.Windows.Forms/src/Resources/xlf/SR.pl.xlf +++ b/src/System.Windows.Forms/src/Resources/xlf/SR.pl.xlf @@ -9511,12 +9511,12 @@ Stos śledzenia, w którym wystąpiła zabroniona operacja: Funkcja nie jest obsługiwana w tym systemie operacyjnym. - + TabPage cannot be added to a '{0}'. TabPages can only be added to TabControls. Nie można dodać elementu TabPage do elementu „{0}”. Elementy TabPage mogą być dodawane tylko do elementów TabControl. - + TabPage cannot be added to another TabPage. TabPages can only be added to TabControls. Nie można dodać elementu TabPage do innego elementu TabPage. Elementy TabPage mogą być dodawane tylko do elementów TabControl. diff --git a/src/System.Windows.Forms/src/Resources/xlf/SR.pt-BR.xlf b/src/System.Windows.Forms/src/Resources/xlf/SR.pt-BR.xlf index 64358552617..cbe8cae65be 100644 --- a/src/System.Windows.Forms/src/Resources/xlf/SR.pt-BR.xlf +++ b/src/System.Windows.Forms/src/Resources/xlf/SR.pt-BR.xlf @@ -9511,12 +9511,12 @@ Rastreamento de pilha em que a operação ilegal ocorreu: Não há suporte para o recurso com este sistema operacional. - + TabPage cannot be added to a '{0}'. TabPages can only be added to TabControls. TabPage não pode ser adicionado a '{0}'. TabPages só podem ser adicionados a TabControls. - + TabPage cannot be added to another TabPage. TabPages can only be added to TabControls. TabPage não pode ser adicionado a outro TabPage. TabPages só podem ser adicionados a TabControls. diff --git a/src/System.Windows.Forms/src/Resources/xlf/SR.ru.xlf b/src/System.Windows.Forms/src/Resources/xlf/SR.ru.xlf index f80154e7d0b..b2562d241c4 100644 --- a/src/System.Windows.Forms/src/Resources/xlf/SR.ru.xlf +++ b/src/System.Windows.Forms/src/Resources/xlf/SR.ru.xlf @@ -9512,12 +9512,12 @@ Stack trace where the illegal operation occurred was: Функция не поддерживается в данной ОС. - + TabPage cannot be added to a '{0}'. TabPages can only be added to TabControls. TabPage нельзя добавить к '{0}'. TabPages можно добавлять только к TabControls. - + TabPage cannot be added to another TabPage. TabPages can only be added to TabControls. TabPage нельзя добавить к другой TabPage. TabPages можно добавлять только к TabControls. diff --git a/src/System.Windows.Forms/src/Resources/xlf/SR.tr.xlf b/src/System.Windows.Forms/src/Resources/xlf/SR.tr.xlf index 0e07de2d6c8..65caa7ebcff 100644 --- a/src/System.Windows.Forms/src/Resources/xlf/SR.tr.xlf +++ b/src/System.Windows.Forms/src/Resources/xlf/SR.tr.xlf @@ -9511,12 +9511,12 @@ Geçersiz işlemin gerçekleştiği yığın izi: Özellik bu işletim sistemiyle desteklenmiyor. - + TabPage cannot be added to a '{0}'. TabPages can only be added to TabControls. '{0}' öğesine TabPage eklenemez. TabPage'ler yalnızca TabControl'lere eklenebilir. - + TabPage cannot be added to another TabPage. TabPages can only be added to TabControls. Bir TabPage başka bir TabPage'e eklenemez. TabPage'ler yalnızca TabControl'lere eklenebilir. diff --git a/src/System.Windows.Forms/src/Resources/xlf/SR.zh-Hans.xlf b/src/System.Windows.Forms/src/Resources/xlf/SR.zh-Hans.xlf index 7a021bd20f4..5f72e45ed7d 100644 --- a/src/System.Windows.Forms/src/Resources/xlf/SR.zh-Hans.xlf +++ b/src/System.Windows.Forms/src/Resources/xlf/SR.zh-Hans.xlf @@ -9511,12 +9511,12 @@ Stack trace where the illegal operation occurred was: 此操作系统不支持该功能。 - + TabPage cannot be added to a '{0}'. TabPages can only be added to TabControls. 无法将 TabPage 添加到“{0}”。 只能将 TabPages 添加到 TabControls。 - + TabPage cannot be added to another TabPage. TabPages can only be added to TabControls. 无法将 TabPage 添加到其他 TabPage。 TabPages 只能添加到 TabControls。 diff --git a/src/System.Windows.Forms/src/Resources/xlf/SR.zh-Hant.xlf b/src/System.Windows.Forms/src/Resources/xlf/SR.zh-Hant.xlf index 49e4c2606c5..56111796c84 100644 --- a/src/System.Windows.Forms/src/Resources/xlf/SR.zh-Hant.xlf +++ b/src/System.Windows.Forms/src/Resources/xlf/SR.zh-Hant.xlf @@ -9511,12 +9511,12 @@ Stack trace where the illegal operation occurred was: 此作業系統不支援這項功能。 - + TabPage cannot be added to a '{0}'. TabPages can only be added to TabControls. 無法將 TabPage 加入 '{0}'。TabPages 只能加入 TabControls。 - + TabPage cannot be added to another TabPage. TabPages can only be added to TabControls. 無法將 TabPage 加入其他 TabPage。TabPages 只能加入 TabControls。 diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs index 9e1bff09545..cdc425c75c7 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs @@ -8128,8 +8128,7 @@ internal virtual void OnInvokedSetScrollPosition(object sender, EventArgs e) [EditorBrowsable(EditorBrowsableState.Advanced)] protected virtual void OnLocationChanged(EventArgs e) { - OnMove(EventArgs.Empty); - + OnMove(e); if (Events[EventLocation] is EventHandler eh) { eh(this, e); diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/TabPage.cs b/src/System.Windows.Forms/src/System/Windows/Forms/TabPage.cs index 455812cc183..72cae1d67fc 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/TabPage.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/TabPage.cs @@ -2,30 +2,27 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.ComponentModel; +using System.Diagnostics; +using System.Drawing; +using System.Drawing.Design; +using System.Runtime.InteropServices; +using System.Text; +using System.Windows.Forms.Layout; + namespace System.Windows.Forms { - using System.ComponentModel; - using System.Diagnostics; - using System; - using System.Drawing; - using System.Drawing.Design; - using System.Text; - using System.Runtime.InteropServices; - using System.Windows.Forms.Layout; - /// - /// TabPage implements a single page of a tab control. It is essentially - /// a Panel with TabItem properties. + /// TabPage implements a single page of a tab control. It is essentially a Panel with TabItem + /// properties. /// - [ - ComVisible(true), - ClassInterface(ClassInterfaceType.AutoDispatch), - Designer("System.Windows.Forms.Design.TabPageDesigner, " + AssemblyRef.SystemDesign), - ToolboxItem(false), - DesignTimeVisible(false), - DefaultEvent("Click"), - DefaultProperty("Text") - ] + [ComVisible(true)] + [ClassInterface(ClassInterfaceType.AutoDispatch)] + [Designer("System.Windows.Forms.Design.TabPageDesigner, " + AssemblyRef.SystemDesign)] + [ToolboxItem(false)] + [DesignTimeVisible(false)] + [DefaultEvent("Click")] + [DefaultProperty("Text")] public class TabPage : Panel { private ImageList.Indexer imageIndexer; @@ -37,28 +34,30 @@ public class TabPage : Panel /// /// Constructs an empty TabPage. /// - public TabPage() - : base() + public TabPage() : base() { SetStyle(ControlStyles.CacheText, true); Text = null; } + /// + /// Constructs a TabPage with text for the tab. + /// + public TabPage(string text) : this() + { + Text = text; + } + /// /// Allows the control to optionally shrink when AutoSize is true. /// - [ - EditorBrowsable(EditorBrowsableState.Never), - DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), - Browsable(false), - Localizable(false) - ] + [EditorBrowsable(EditorBrowsableState.Never)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [Browsable(false),] + [Localizable(false)] public override AutoSizeMode AutoSizeMode { - get - { - return AutoSizeMode.GrowOnly; - } + get => AutoSizeMode.GrowOnly; set { } @@ -67,52 +66,45 @@ public override AutoSizeMode AutoSizeMode /// /// Hide AutoSize: it doesn't make sense for this control /// - [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public override bool AutoSize { - get - { - return base.AutoSize; - } - set - { - base.AutoSize = value; - } + get => base.AutoSize; + set => base.AutoSize = value; } - [SRCategory(nameof(SR.CatPropertyChanged)), SRDescription(nameof(SR.ControlOnAutoSizeChangedDescr))] - [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] - new public event EventHandler AutoSizeChanged + [SRCategory(nameof(SR.CatPropertyChanged))] + [SRDescription(nameof(SR.ControlOnAutoSizeChangedDescr))] + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler AutoSizeChanged { add => base.AutoSizeChanged += value; remove => base.AutoSizeChanged -= value; } /// - /// The background color of this control. This is an ambient property and - /// will always return a non-null value. + /// The background color of this control. This is an ambient property and will always return + /// a non-null value. /// - [ - SRCategory(nameof(SR.CatAppearance)), - SRDescription(nameof(SR.ControlBackColorDescr)) - ] + [SRCategory(nameof(SR.CatAppearance))] + [SRDescription(nameof(SR.ControlBackColorDescr))] public override Color BackColor { get { Color color = base.BackColor; - // If some color is Set by the user return that... if (color != DefaultBackColor) { return color; } - // If user has not set a color and if theming ON and Parent's appearance is Normal, then return the Transparent Color.... - if (Application.RenderWithVisualStyles && UseVisualStyleBackColor && (ParentInternal is TabControl parent && parent.Appearance == TabAppearance.Normal)) + else if (Application.RenderWithVisualStyles && UseVisualStyleBackColor && (ParentInternal is TabControl parent && parent.Appearance == TabAppearance.Normal)) { return Color.Transparent; } - // return base.Color by default... + return color; } set @@ -139,51 +131,30 @@ public override Color BackColor } /// - /// Constructs the new instance of the Controls collection objects. Subclasses - /// should not call base.CreateControlsInstance. Our version creates a control - /// collection that does not support + /// Constructs the new instance of the Controls collection objects. /// - protected override ControlCollection CreateControlsInstance() - { - return new TabPageControlCollection(this); - } - - internal ImageList.Indexer ImageIndexer - { - get - { - if (imageIndexer == null) - { - imageIndexer = new ImageList.Indexer(); - } + protected override ControlCollection CreateControlsInstance() => new TabPageControlCollection(this); - return imageIndexer; - } - } + internal ImageList.Indexer ImageIndexer => imageIndexer ??= new ImageList.Indexer(); /// - /// Returns the imageIndex for the tabPage. This should point to an image + /// Returns the imageIndex for the TabPage. This should point to an image /// in the TabControl's associated imageList that will appear on the tab, or be -1. /// - [ - TypeConverter(typeof(ImageIndexConverter)), - Editor("System.Windows.Forms.Design.ImageIndexEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor)), - Localizable(true), - RefreshProperties(RefreshProperties.Repaint), - DefaultValue(-1), - SRDescription(nameof(SR.TabItemImageIndexDescr)) - ] + [TypeConverter(typeof(ImageIndexConverter))] + [Editor("System.Windows.Forms.Design.ImageIndexEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor))] + [Localizable(true)] + [RefreshProperties(RefreshProperties.Repaint)] + [DefaultValue(-1)] + [SRDescription(nameof(SR.TabItemImageIndexDescr))] public int ImageIndex { - get - { - return ImageIndexer.Index; - } + get => ImageIndexer.Index; set { if (value < -1) { - throw new ArgumentOutOfRangeException(nameof(value), string.Format(SR.InvalidLowBoundArgumentEx, nameof(ImageIndex), value, -1)); + throw new ArgumentOutOfRangeException(nameof(value), value, string.Format(SR.InvalidLowBoundArgumentEx, nameof(ImageIndex), value, -1)); } if (ParentInternal is TabControl parent) @@ -197,23 +168,18 @@ public int ImageIndex } /// - /// Returns the imageIndex for the tabPage. This should point to an image - /// in the TabControl's associated imageList that will appear on the tab, or be -1. + /// Returns the imageIndex for the TabPage. This should point to an image in the TabControl's + /// associated imageList that will appear on the tab, or be -1. /// - [ - TypeConverter(typeof(ImageKeyConverter)), - Editor("System.Windows.Forms.Design.ImageIndexEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor)), - Localizable(true), - DefaultValue(""), - RefreshProperties(RefreshProperties.Repaint), - SRDescription(nameof(SR.TabItemImageIndexDescr)) - ] + [TypeConverter(typeof(ImageKeyConverter))] + [Editor("System.Windows.Forms.Design.ImageIndexEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor))] + [Localizable(true)] + [DefaultValue("")] + [RefreshProperties(RefreshProperties.Repaint)] + [SRDescription(nameof(SR.TabItemImageIndexDescr))] public string ImageKey { - get - { - return ImageIndexer.Key; - } + get => ImageIndexer.Key; set { ImageIndexer.Key = value; @@ -227,198 +193,151 @@ public string ImageKey } } - /// - /// Constructs a TabPage with text for the tab. - /// - public TabPage(string text) : this() - { - Text = text; - } - - [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] public override AnchorStyles Anchor { - get - { - return base.Anchor; - } - set - { - base.Anchor = value; - } + get => base.Anchor; + set => base.Anchor = value; } - [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] public override DockStyle Dock { - get - { - return base.Dock; - } - set - { - base.Dock = value; - } + get => base.Dock; + set => base.Dock = value; } - [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] - new public event EventHandler DockChanged + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler DockChanged { add => base.DockChanged += value; remove => base.DockChanged -= value; } - [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] - new public bool Enabled + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public new bool Enabled { - get - { - return base.Enabled; - } - set - { - base.Enabled = value; - } + get => base.Enabled; + set => base.Enabled = value; } - [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] - new public event EventHandler EnabledChanged + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler EnabledChanged { add => base.EnabledChanged += value; remove => base.EnabledChanged -= value; } - [ - DefaultValue(false), - SRCategory(nameof(SR.CatAppearance)), - SRDescription(nameof(SR.TabItemUseVisualStyleBackColorDescr)) - ] + [DefaultValue(false)] + [SRCategory(nameof(SR.CatAppearance))] + [SRDescription(nameof(SR.TabItemUseVisualStyleBackColorDescr))] public bool UseVisualStyleBackColor { - get - { - return useVisualStyleBackColor; - } + get => useVisualStyleBackColor; set { + if (useVisualStyleBackColor == value) + { + return; + } + useVisualStyleBackColor = value; Invalidate(true); } } - // Make the Location property non-browsable for the TabPages. - [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] - new public Point Location + /// + /// Make the Location property non-browsable for the tab pages. + /// + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public new Point Location { - get - { - return base.Location; - } - set - { - base.Location = value; - } + get => base.Location; + set => base.Location = value; } - [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] - new public event EventHandler LocationChanged + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler LocationChanged { add => base.LocationChanged += value; remove => base.LocationChanged -= value; } [DefaultValue(typeof(Size), "0, 0")] - [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] public override Size MaximumSize { - get { return base.MaximumSize; } + get => base.MaximumSize; - set - { - base.MaximumSize = value; - } + set => base.MaximumSize = value; } - [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] public override Size MinimumSize { - get { return base.MinimumSize; } + get => base.MinimumSize; - set - { - base.MinimumSize = value; - } + set => base.MinimumSize = value; } - [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] - public new Size PreferredSize - { - get { return base.PreferredSize; } - } + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public new Size PreferredSize => base.PreferredSize; - [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] - new public int TabIndex + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public new int TabIndex { - get - { - return base.TabIndex; - } - set - { - base.TabIndex = value; - } + get => base.TabIndex; + set => base.TabIndex = value; } /// - /// This property is required by certain controls (TabPage) to render its transparency using theming API. - /// We dont want all controls (that are have transparent BackColor) to use theming API to render its background because it has HUGE PERF cost. + /// This property is required by certain controls (TabPage) to render its transparency using + /// theming API. We dont want all controls (that are have transparent BackColor) to use + /// theming API to render its background because it has large performance cost. /// - internal override bool RenderTransparencyWithVisualStyles - { - get - { - return true; - } - } + internal override bool RenderTransparencyWithVisualStyles => true; - [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] - new public event EventHandler TabIndexChanged + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler TabIndexChanged { add => base.TabIndexChanged += value; remove => base.TabIndexChanged -= value; } - [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] - new public bool TabStop + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public new bool TabStop { - get - { - return base.TabStop; - } - set - { - base.TabStop = value; - } + get => base.TabStop; + set => base.TabStop = value; } - [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] - new public event EventHandler TabStopChanged + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler TabStopChanged { add => base.TabStopChanged += value; remove => base.TabStopChanged -= value; } - [ - Localizable(true), - Browsable(true), - EditorBrowsable(EditorBrowsableState.Always) - ] + [Localizable(true)] + [Browsable(true)] + [EditorBrowsable(EditorBrowsableState.Always)] public override string Text { - get - { - return base.Text; - } + get => base.Text; set { base.Text = value; @@ -426,28 +345,24 @@ public override string Text } } - [Browsable(true), EditorBrowsable(EditorBrowsableState.Always)] - new public event EventHandler TextChanged + [Browsable(true)] + [EditorBrowsable(EditorBrowsableState.Always)] + public new event EventHandler TextChanged { add => base.TextChanged += value; remove => base.TextChanged -= value; } /// - /// The toolTipText for the tab, that will appear when the mouse hovers - /// over the tab and the TabControl's showToolTips property is true. + /// The toolTipText for the tab, that will appear when the mouse hovers over the tab and the + /// TabControl's showToolTips property is true. /// - [ - DefaultValue(""), - Localizable(true), - SRDescription(nameof(SR.TabItemToolTipTextDescr)) - ] + [DefaultValue("")] + [Localizable(true)] + [SRDescription(nameof(SR.TabItemToolTipTextDescr))] public string ToolTipText { - get - { - return toolTipText; - } + get => toolTipText; set { if (value == null) @@ -465,53 +380,47 @@ public string ToolTipText } } - [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] - new public bool Visible + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public new bool Visible { - get - { - return base.Visible; - } - set - { - base.Visible = value; - } + get => base.Visible; + set => base.Visible = value; } - [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] - new public event EventHandler VisibleChanged + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler VisibleChanged { add => base.VisibleChanged += value; remove => base.VisibleChanged -= value; } /// - /// Assigns a new parent control. Sends out the appropriate property change - /// notifications for properties that are affected by the change of parent. + /// Assigns a new parent control. Sends out the appropriate property change notifications for + /// properties that are affected by the change of parent. /// internal override void AssignParent(Control value) { if (value != null && !(value is TabControl)) { - throw new ArgumentException(string.Format(SR.TABCONTROLTabPageNotOnTabControl, value.GetType().FullName)); + throw new ArgumentException(string.Format(SR.TabControlTabPageNotOnTabControl, value.GetType().FullName)); } base.AssignParent(value); } /// - /// Given a component, this retrieves the tab page that it's parented to, or - /// null if it's not parented to any tab page. + /// Given a component, this retrieves the tab page that it's parented to, or null if it's not + /// parented to any tab page. /// public static TabPage GetTabPageOfComponent(object comp) { - if (!(comp is Control)) + if (!(comp is Control c)) { return null; } - Control c = (Control)comp; - while (c != null && !(c is TabPage)) { c = c.ParentInternal; @@ -553,32 +462,27 @@ private void PrefixAmpersands(ref string value) // text string, but the accelerators don't work. // So in this function, we prefix ampersands with another ampersand // so that they actually appear as ampersands. - // - // Sanity check parameter - // - if (value == null || value.Length == 0) + if (string.IsNullOrEmpty(value)) { return; } // If there are no ampersands, we don't need to do anything here - // if (value.IndexOf('&') < 0) { return; } // Insert extra ampersands - // - StringBuilder newString = new StringBuilder(); - + var newString = new StringBuilder(); for (int i = 0; i < value.Length; ++i) { if (value[i] == '&') { if (i < value.Length - 1 && value[i + 1] == '&') { - ++i; // Skip the second ampersand + // Skip the second ampersand + ++i; } newString.Append("&&"); @@ -593,7 +497,7 @@ private void PrefixAmpersands(ref string value) } /// - /// This is an internal method called by the TabControl to fire the Leave event when TabControl leave occurs. + /// This is an internal method called by the TabControl to fire the Leave event when TabControl leave occurs. /// internal void FireLeave(EventArgs e) { @@ -602,7 +506,7 @@ internal void FireLeave(EventArgs e) } /// - /// This is an internal method called by the TabControl to fire the Enter event when TabControl leave occurs. + /// This is an internal method called by the TabControl to fire the Enter event when TabControl leave occurs. /// internal void FireEnter(EventArgs e) { @@ -611,14 +515,12 @@ internal void FireEnter(EventArgs e) } /// - /// Actually goes and fires the OnEnter event. Inheriting controls - /// should use this to know when the event is fired [this is preferable to - /// adding an event handler on yourself for this event]. They should, - /// however, remember to call base.OnEnter(e); to ensure the event is - /// still fired to external listeners - /// This listener is overidden so that we can fire SAME ENTER and LEAVE - /// events on the TabPage. - /// TabPage should fire enter when the focus is on the TABPAGE and not when the control + /// Actually goes and fires the OnEnter event. Inheriting controls should use this to know + /// when the event is fired [this is preferable to adding an event handler on yourself for + /// this event]. They should, however, remember to call base.OnEnter(e); to ensure the event + /// i still fired to external listeners + /// This listener is overidden so that we can fire SAME ENTER and LEAVE events on the TabPage. + /// TabPage should fire enter when the focus is on the TabPage and not when the control /// within the TabPage gets Focused. /// protected override void OnEnter(EventArgs e) @@ -635,17 +537,14 @@ protected override void OnEnter(EventArgs e) } /// - /// Actually goes and fires the OnLeave event. Inheriting controls - /// should use this to know when the event is fired [this is preferable to - /// adding an event handler on yourself for this event]. They should, - /// however, remember to call base.OnLeave(e); to ensure the event is - /// still fired to external listeners - /// This listener is overidden so that we can fire SAME ENTER and LEAVE - /// events on the TabPage. - /// TabPage should fire enter when the focus is on the TABPAGE and not when the control - /// within the TabPage gets Focused. - /// Similary the Leave should fire when the TabControl (and hence the TabPage) looses - /// Focus. + /// Actually goes and fires the OnLeave event. Inheriting controls should use this to know + /// when the event is fired [this is preferable to adding an event handler on yourself for + /// this event]. They should, however, remember to call base.OnLeave(e); to ensure the event + /// is still fired to external listeners + /// This listener is overidden so that we can fire same enter and leave events on the TabPage. + /// TabPage should fire enter when the focus is on the TabPage and not when the control within + /// the TabPage gets Focused. + /// Similary the Leave should fire when the TabControl (and hence the TabPage) loses focus. /// protected override void OnLeave(EventArgs e) { @@ -662,35 +561,26 @@ protected override void OnLeave(EventArgs e) protected override void OnPaintBackground(PaintEventArgs e) { - // Utilize the TabRenderer new to Whidbey to draw the tab pages so that the - // panels are drawn using the correct visual styles when the application supports using visual + // Utilize the TabRenderer new to Whidbey to draw the tab pages so that the panels are + // drawn using the correct visual styles when the application supports using visual // styles. - // Does this application utilize Visual Styles? - // Utilize the UseVisualStyleBackColor property to determine whether or - // not the themed background should be utilized. + // Utilize the UseVisualStyleBackColor property to determine whether or not the themed + // background should be utilized. if (Application.RenderWithVisualStyles && UseVisualStyleBackColor && (ParentInternal is TabControl parent && parent.Appearance == TabAppearance.Normal)) { - Color bkcolor = UseVisualStyleBackColor ? Color.Transparent : BackColor; Rectangle inflateRect = LayoutUtils.InflateRect(DisplayRectangle, Padding); - //To ensure that the tabpage draws correctly (the border will get clipped and - // and gradient fill will match correctly with the tabcontrol). Unfortunately, there is no good way to determine - // the padding used on the tabpage. - // I would like to use the following below, but GetMargins is busted in the theming API: - //VisualStyleRenderer visualStyleRenderer = new VisualStyleRenderer(VisualStyleElement.Tab.Pane.Normal); - //Padding themePadding = visualStyleRenderer.GetMargins(e.Graphics, MarginProperty.ContentMargins); - //Rectangle rectWithBorder = new Rectangle(inflateRect.X - themePadding.Left, - // inflateRect.Y - themePadding.Top, - // inflateRect.Width + themePadding.Right + themePadding.Left, - // inflateRect.Height + themePadding.Bottom + themePadding.Top); + // To ensure that the TabPage draws correctly (the border will get clipped and + // and gradient fill will match correctly with the tabcontrol). Unfortunately, + // there is no good way to determine the padding used on the TabPage. Rectangle rectWithBorder = new Rectangle(inflateRect.X - 4, inflateRect.Y - 2, inflateRect.Width + 8, inflateRect.Height + 6); TabRenderer.DrawTabPage(e.Graphics, rectWithBorder); - // Is there a background image to paint? The TabRenderer does not currently support - // painting the background image on the panel, so we need to draw it ourselves. + // TabRenderer does not support painting the background image on the panel, so + // draw it ourselves. if (BackgroundImage != null) { ControlPaint.DrawBackgroundImage(e.Graphics, BackgroundImage, bkcolor, BackgroundImageLayout, inflateRect, inflateRect, DisplayRectangle.Location); @@ -703,8 +593,8 @@ protected override void OnPaintBackground(PaintEventArgs e) } /// - /// overrides main setting of our bounds so that we can control our size and that of our - /// TabPages... + /// Overrides main setting of our bounds so that we can control our size and that of our + /// TabPages. /// protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified) { @@ -715,7 +605,7 @@ protected override void SetBoundsCore(int x, int y, int width, int height, Bound Rectangle r = parent.DisplayRectangle; // LayoutEngines send BoundsSpecified.None so they can know they are the ones causing the size change - // in the subsequent InitLayout. We need to be careful preserve a None. + // in the subsequent InitLayout. We need to be careful preserve a None. base.SetBoundsCore(r.X, r.Y, r.Width, r.Height, specified == BoundsSpecified.None ? BoundsSpecified.None : BoundsSpecified.All); } else @@ -728,18 +618,12 @@ protected override void SetBoundsCore(int x, int y, int width, int height, Bound /// Determines if the Location property needs to be persisted. /// [EditorBrowsable(EditorBrowsableState.Never)] - private bool ShouldSerializeLocation() - { - return Left != 0 || Top != 0; - } + private bool ShouldSerializeLocation() => Left != 0 || Top != 0; /// /// The text property is what is returned for the TabPages default printing. /// - public override string ToString() - { - return "TabPage: {" + Text + "}"; - } + public override string ToString() => $"TabPage: {{{Text}}}"; internal void UpdateParent() { @@ -765,7 +649,7 @@ public TabPageControlCollection(TabPage owner) : base(owner) /// /// Adds a child control to this control. The control becomes the last control /// in the child control list. If the control is already a child of another - /// control it is first removed from that control. The tab page overrides + /// control it is first removed from that control. The tab page overrides /// this method to ensure that child tab pages are not added to it, as these /// are illegal. /// @@ -773,7 +657,7 @@ public override void Add(Control value) { if (value is TabPage) { - throw new ArgumentException(SR.TABCONTROLTabPageOnTabPage); + throw new ArgumentException(SR.TabControlTabPageOnTabPage); } base.Add(value); @@ -781,4 +665,3 @@ public override void Add(Control value) } } } - diff --git a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ControlTests.cs b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ControlTests.cs index da94f44a874..2e62bf5b9c5 100644 --- a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ControlTests.cs +++ b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ControlTests.cs @@ -1890,7 +1890,7 @@ public void Control_TopGetSet(int expected) [Theory] [CommonMemberData(nameof(CommonTestHelper.GetPointTheoryData))] - public void Control_LocationGetSet(Point value) + public void Control_Location_Set_GetReturnsExpected(Point value) { var control = new Control { @@ -1903,6 +1903,131 @@ public void Control_LocationGetSet(Point value) Assert.Equal(value, control.Location); } + [Theory] + [CommonMemberData(nameof(CommonTestHelper.GetPointTheoryData))] + public void Control_Location_SetWithParent_GetReturnsExpected(Point value) + { + var parent = new Control(); + var control = new Control + { + Parent = parent, + Location = value + }; + Assert.Equal(value, control.Location); + + // Set same. + control.Location = value; + Assert.Equal(value, control.Location); + } + + [Fact] + public void Control_Location_SetWithHandle_DoesNotCallInvalidate() + { + var control = new Control(); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + + // Set different. + control.Location = new Point(1, 2); + Assert.Equal(new Point(1, 2), control.Location); + Assert.Equal(0, invalidatedCallCount); + + // Set same. + control.Location = new Point(1, 2); + Assert.Equal(new Point(1, 2), control.Location); + Assert.Equal(0, invalidatedCallCount); + + // Set different. + control.Location = new Point(2, 3); + Assert.Equal(new Point(2, 3), control.Location); + Assert.Equal(0, invalidatedCallCount); + } + + [Theory] + [InlineData(true, 1)] + [InlineData(false, 0)] + public void Control_Location_SetWithHandleWithTransparentBackColor_DoesNotCallInvalidate(bool supportsTransparentBackgroundColor, int expectedInvalidatedCallCount) + { + var control = new SubControl(); + control.SetStyle(ControlStyles.SupportsTransparentBackColor, true); + control.BackColor = Color.FromArgb(254, 255, 255, 255); + control.SetStyle(ControlStyles.SupportsTransparentBackColor, supportsTransparentBackgroundColor); + + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + + // Set different. + control.Location = new Point(1, 2); + Assert.Equal(new Point(1, 2), control.Location); + Assert.Equal(expectedInvalidatedCallCount, invalidatedCallCount); + + // Set same. + control.Location = new Point(1, 2); + Assert.Equal(new Point(1, 2), control.Location); + Assert.Equal(expectedInvalidatedCallCount, invalidatedCallCount); + + // Set different. + control.Location = new Point(2, 3); + Assert.Equal(new Point(2, 3), control.Location); + Assert.Equal(expectedInvalidatedCallCount * 2, invalidatedCallCount); + } + + [Fact] + public void Control_Location_SetWithHandler_CallsLocationChanged() + { + var control = new Control(); + int locationChangedCallCount = 0; + EventHandler locationChangedHandler = (sender, e) => + { + Assert.Same(control, sender); + Assert.Same(EventArgs.Empty, e); + locationChangedCallCount++; + }; + control.LocationChanged += locationChangedHandler; + int moveCallCount = 0; + EventHandler moveHandler = (sender, e) => + { + Assert.Same(control, sender); + Assert.Same(EventArgs.Empty, e); + moveCallCount++; + }; + control.Move += moveHandler; + + // Set different. + control.Location = new Point(1, 2); + Assert.Equal(new Point(1, 2), control.Location); + Assert.Equal(1, locationChangedCallCount); + Assert.Equal(1, moveCallCount); + + // Set same. + control.Location = new Point(1, 2); + Assert.Equal(new Point(1, 2), control.Location); + Assert.Equal(1, locationChangedCallCount); + Assert.Equal(1, moveCallCount); + + // Set different x. + control.Location = new Point(2, 2); + Assert.Equal(new Point(2, 2), control.Location); + Assert.Equal(2, locationChangedCallCount); + Assert.Equal(2, moveCallCount); + + // Set different y. + control.Location = new Point(2, 3); + Assert.Equal(new Point(2, 3), control.Location); + Assert.Equal(3, locationChangedCallCount); + Assert.Equal(3, moveCallCount); + + // Remove handler. + control.LocationChanged -= locationChangedHandler; + control.Move -= moveHandler; + control.Location = new Point(1, 2); + Assert.Equal(new Point(1, 2), control.Location); + Assert.Equal(3, locationChangedCallCount); + Assert.Equal(3, moveCallCount); + } + [Theory] [CommonMemberData(nameof(CommonTestHelper.GetPaddingNormalizedTheoryData))] public void Control_Margin_Set_GetReturnsExpected(Padding value, Padding expected) @@ -2149,18 +2274,6 @@ public void Control_ControlAddedAndRemoved() Assert.True(wasRemoved); } - [Fact] - public void Control_LocationChanged() - { - bool wasChanged = false; - var cont = new Control(); - cont.LocationChanged += (sender, args) => wasChanged = true; - - cont.Location = new Point(1, 1); - - Assert.True(wasChanged); - } - [Theory] [CommonMemberData(nameof(CommonTestHelper.GetFontTheoryData))] public void Control_Font_Set_GetReturnsExpected(Font value) @@ -4005,26 +4118,135 @@ public void Control_OnLayout_Invoke_CallsLayout(LayoutEventArgs eventArgs) [Theory] [CommonMemberData(nameof(CommonTestHelper.GetEventArgsTheoryData))] - public void Control_OnLeave_Invoke_CallsLeave(EventArgs eventArgs) + public void Control_OnLocationChanged_Invoke_CallsLocationChangedAndMove(EventArgs eventArgs) { var control = new SubControl(); - int callCount = 0; - EventHandler handler = (sender, e) => + int locationChangedCallCount = 0; + EventHandler locationChangedHandler = (sender, e) => { Assert.Same(control, sender); Assert.Same(eventArgs, e); - callCount++; + locationChangedCallCount++; + }; + int moveCallCount = 0; + EventHandler moveHandler = (sender, e) => + { + Assert.Same(control, sender); + Assert.Same(eventArgs, e); + moveCallCount++; }; // Call with handler. - control.Leave += handler; - control.OnLeave(eventArgs); - Assert.Equal(1, callCount); + control.LocationChanged += locationChangedHandler; + control.Move += moveHandler; + control.OnLocationChanged(eventArgs); + Assert.Equal(1, locationChangedCallCount); + Assert.Equal(1, moveCallCount); // Remove handler. - control.Leave -= handler; - control.OnLeave(eventArgs); - Assert.Equal(1, callCount); + control.LocationChanged -= locationChangedHandler; + control.Move -= moveHandler; + control.OnLocationChanged(eventArgs); + Assert.Equal(1, locationChangedCallCount); + Assert.Equal(1, moveCallCount); + } + + [Theory] + [CommonMemberData(nameof(CommonTestHelper.GetEventArgsTheoryData))] + public void Control_OnLocationChanged_InvokeWithHandle_CallsLocationChangedAndMove(EventArgs eventArgs) + { + var control = new SubControl(); + Assert.NotEqual(IntPtr.Zero, control.Handle); + + int locationChangedCallCount = 0; + EventHandler locationChangedHandler = (sender, e) => + { + Assert.Same(control, sender); + Assert.Same(eventArgs, e); + locationChangedCallCount++; + }; + int moveCallCount = 0; + EventHandler moveHandler = (sender, e) => + { + Assert.Same(control, sender); + Assert.Same(eventArgs, e); + moveCallCount++; + }; + int invalidatedCallCount = 0; + InvalidateEventHandler invalidatedHandler = (sender, e) => invalidatedCallCount++; + + // Call with handler. + control.LocationChanged += locationChangedHandler; + control.Move += moveHandler; + control.Invalidated += invalidatedHandler; + control.OnLocationChanged(eventArgs); + Assert.Equal(1, locationChangedCallCount); + Assert.Equal(1, moveCallCount); + Assert.Equal(0, invalidatedCallCount); + + // Remove handler. + control.LocationChanged -= locationChangedHandler; + control.Move -= moveHandler; + control.Invalidated -= invalidatedHandler; + control.OnLocationChanged(eventArgs); + Assert.Equal(1, locationChangedCallCount); + Assert.Equal(1, moveCallCount); + Assert.Equal(0, invalidatedCallCount); + } + + public static IEnumerable OnLocationChanged_HandleWithTransparentBackColor_TestData() + { + foreach (object[] testData in CommonTestHelper.GetEventArgsTheoryData()) + { + yield return new object[] { true, testData[0], 1 }; + yield return new object[] { false, testData[0], 0 }; + } + } + + [Theory] + [MemberData(nameof(OnLocationChanged_HandleWithTransparentBackColor_TestData))] + public void Control_OnLocationChanged_InvokeWithHandleWithTransparentBackColor_CallsLocationChangedAndMoveAndInvalidated(bool supportsTransparentBackgroundColor, EventArgs eventArgs, int expectedInvalidatedCallCount) + { + var control = new SubControl(); + control.SetStyle(ControlStyles.SupportsTransparentBackColor, true); + control.BackColor = Color.FromArgb(254, 255, 255, 255); + control.SetStyle(ControlStyles.SupportsTransparentBackColor, supportsTransparentBackgroundColor); + Assert.NotEqual(IntPtr.Zero, control.Handle); + + int locationChangedCallCount = 0; + EventHandler locationChangedHandler = (sender, e) => + { + Assert.Same(control, sender); + Assert.Same(eventArgs, e); + locationChangedCallCount++; + }; + int moveCallCount = 0; + EventHandler moveHandler = (sender, e) => + { + Assert.Same(control, sender); + Assert.Same(eventArgs, e); + moveCallCount++; + }; + int invalidatedCallCount = 0; + InvalidateEventHandler invalidatedHandler = (sender, e) => invalidatedCallCount++; + + // Call with handler. + control.LocationChanged += locationChangedHandler; + control.Move += moveHandler; + control.Invalidated += invalidatedHandler; + control.OnLocationChanged(eventArgs); + Assert.Equal(1, locationChangedCallCount); + Assert.Equal(1, moveCallCount); + Assert.Equal(expectedInvalidatedCallCount, invalidatedCallCount); + + // Remove handler. + control.LocationChanged -= locationChangedHandler; + control.Move -= moveHandler; + control.Invalidated -= invalidatedHandler; + control.OnLocationChanged(eventArgs); + Assert.Equal(1, locationChangedCallCount); + Assert.Equal(1, moveCallCount); + Assert.Equal(expectedInvalidatedCallCount, invalidatedCallCount); } [Theory] @@ -4191,6 +4413,97 @@ public void Control_OnMouseWheel_InvokeHandledMouseEventArgs_DoesNotSetHandled() Assert.False(eventArgs.Handled); } + [Theory] + [CommonMemberData(nameof(CommonTestHelper.GetEventArgsTheoryData))] + public void Control_OnMove_Invoke_CallsMove(EventArgs eventArgs) + { + var control = new SubControl(); + int moveCallCount = 0; + EventHandler moveHandler = (sender, e) => + { + Assert.Same(control, sender); + Assert.Same(eventArgs, e); + moveCallCount++; + }; + + // Call with handler. + control.Move += moveHandler; + control.OnMove(eventArgs); + Assert.Equal(1, moveCallCount); + + // Remove handler. + control.Move -= moveHandler; + control.OnMove(eventArgs); + Assert.Equal(1, moveCallCount); + } + + [Theory] + [CommonMemberData(nameof(CommonTestHelper.GetEventArgsTheoryData))] + public void Control_OnMove_InvokeWithHandle_CallsMove(EventArgs eventArgs) + { + var control = new SubControl(); + Assert.NotEqual(IntPtr.Zero, control.Handle); + + int moveCallCount = 0; + EventHandler moveHandler = (sender, e) => + { + Assert.Same(control, sender); + Assert.Same(eventArgs, e); + moveCallCount++; + }; + int invalidatedCallCount = 0; + InvalidateEventHandler invalidatedHandler = (sender, e) => invalidatedCallCount++; + + // Call with handler. + control.Move += moveHandler; + control.Invalidated += invalidatedHandler; + control.OnMove(eventArgs); + Assert.Equal(1, moveCallCount); + Assert.Equal(0, invalidatedCallCount); + + // Remove handler. + control.Move -= moveHandler; + control.Invalidated -= invalidatedHandler; + control.OnMove(eventArgs); + Assert.Equal(1, moveCallCount); + Assert.Equal(0, invalidatedCallCount); + } + + [Theory] + [MemberData(nameof(OnLocationChanged_HandleWithTransparentBackColor_TestData))] + public void Control_OnMove_InvokeWithHandleWithTransparentBackColor_CallsMoveAndInvalidated(bool supportsTransparentBackgroundColor, EventArgs eventArgs, int expectedInvalidatedCallCount) + { + var control = new SubControl(); + control.SetStyle(ControlStyles.SupportsTransparentBackColor, true); + control.BackColor = Color.FromArgb(254, 255, 255, 255); + control.SetStyle(ControlStyles.SupportsTransparentBackColor, supportsTransparentBackgroundColor); + Assert.NotEqual(IntPtr.Zero, control.Handle); + + int moveCallCount = 0; + EventHandler moveHandler = (sender, e) => + { + Assert.Same(control, sender); + Assert.Same(eventArgs, e); + moveCallCount++; + }; + int invalidatedCallCount = 0; + InvalidateEventHandler invalidatedHandler = (sender, e) => invalidatedCallCount++; + + // Call with handler. + control.Move += moveHandler; + control.Invalidated += invalidatedHandler; + control.OnMove(eventArgs); + Assert.Equal(1, moveCallCount); + Assert.Equal(expectedInvalidatedCallCount, invalidatedCallCount); + + // Remove handler. + control.Move -= moveHandler; + control.Invalidated -= invalidatedHandler; + control.OnMove(eventArgs); + Assert.Equal(1, moveCallCount); + Assert.Equal(expectedInvalidatedCallCount, invalidatedCallCount); + } + [Theory] [CommonMemberData(nameof(CommonTestHelper.GetPaintEventArgsTheoryData))] public void Control_OnPaint_Invoke_CallsPaint(PaintEventArgs eventArgs) @@ -4423,6 +4736,8 @@ public SubControl(Control parent, string text, int left, int top, int width, int public new void OnLeave(EventArgs e) => base.OnLeave(e); + public new void OnLocationChanged(EventArgs e) => base.OnLocationChanged(e); + public new void OnMouseClick(MouseEventArgs e) => base.OnMouseClick(e); public new void OnMouseDoubleClick(MouseEventArgs e) => base.OnMouseDoubleClick(e); @@ -4435,6 +4750,8 @@ public SubControl(Control parent, string text, int left, int top, int width, int public new void OnMouseWheel(MouseEventArgs e) => base.OnMouseWheel(e); + public new void OnMove(EventArgs e) => base.OnMove(e); + public new void OnPaint(PaintEventArgs e) => base.OnPaint(e); public new void OnParentChanged(EventArgs e) => base.OnParentChanged(e); diff --git a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/TabControlTests.cs b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/TabControlTests.cs new file mode 100644 index 00000000000..651d23d51ca --- /dev/null +++ b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/TabControlTests.cs @@ -0,0 +1,261 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using WinForms.Common.Tests; +using Xunit; + +namespace System.Windows.Forms.Tests +{ + public class TabControlTests + { + [Fact] + public void TabControl_Ctor_Default() + { + var control = new SubTabControl(); + Assert.Equal(TabAlignment.Top, control.Alignment); + Assert.False(control.AllowDrop); + Assert.Equal(TabAppearance.Normal, control.Appearance); + Assert.Equal(AnchorStyles.Top | AnchorStyles.Left, control.Anchor); + Assert.False(control.AutoSize); + Assert.Equal(Control.DefaultBackColor, control.BackColor); + Assert.Null(control.BackgroundImage); + Assert.Equal(ImageLayout.Tile, control.BackgroundImageLayout); + Assert.Null(control.BindingContext); + Assert.Equal(100, control.Bottom); + Assert.Equal(new Rectangle(0, 0, 200, 100), control.Bounds); + Assert.True(control.CanRaiseEvents); + Assert.Equal(new Rectangle(0, 0, 200, 100), control.ClientRectangle); + Assert.Equal(new Size(200, 100), control.ClientSize); + Assert.Null(control.Container); + Assert.True(control.CausesValidation); + Assert.Empty(control.Controls); + Assert.Same(control.Controls, control.Controls); + Assert.False(control.Created); + Assert.Same(Cursors.Default, control.Cursor); + Assert.Same(Cursors.Default, control.DefaultCursor); + Assert.Equal(ImeMode.Inherit, control.DefaultImeMode); + Assert.Equal(new Padding(3), control.DefaultMargin); + Assert.Equal(Size.Empty, control.DefaultMaximumSize); + Assert.Equal(Size.Empty, control.DefaultMinimumSize); + Assert.Equal(Padding.Empty, control.DefaultPadding); + Assert.Equal(new Size(200, 100), control.DefaultSize); + Assert.False(control.DesignMode); + Assert.Equal(DockStyle.None, control.Dock); + Assert.False(control.DoubleBuffered); + Assert.Equal(TabDrawMode.Normal, control.DrawMode); + Assert.True(control.Enabled); + Assert.NotNull(control.Events); + Assert.Same(control.Events, control.Events); + Assert.Equal(Control.DefaultFont, control.Font); + Assert.Equal(Control.DefaultForeColor, control.ForeColor); + Assert.False(control.HasChildren); + Assert.Equal(100, control.Height); + Assert.False(control.HotTrack); + Assert.Null(control.ImageList); + Assert.Equal(ImeMode.NoControl, control.ImeMode); + Assert.Equal(ImeMode.NoControl, control.ImeModeBase); + Assert.Equal(Size.Empty, control.ItemSize); + Assert.Equal(0, control.Left); + Assert.Equal(Point.Empty, control.Location); + Assert.False(control.Multiline); + Assert.Equal(new Point(6, 3), control.Padding); + Assert.Equal(200, control.Right); + Assert.Equal(RightToLeft.No, control.RightToLeft); + Assert.False(control.RightToLeftLayout); + Assert.Equal(-1, control.SelectedIndex); + Assert.Null(control.SelectedTab); + Assert.False(control.ShowToolTips); + Assert.Null(control.Site); + Assert.Equal(new Size(200, 100), control.Size); + Assert.Equal(TabSizeMode.Normal, control.SizeMode); + Assert.Equal(0, control.TabCount); + Assert.Equal(0, control.TabIndex); + Assert.Empty(control.TabPages); + Assert.Same(control.TabPages, control.TabPages); + Assert.True(control.TabStop); + Assert.Empty(control.Text); + Assert.Equal(0, control.Top); + Assert.True(control.Visible); + Assert.Equal(200, control.Width); + + Assert.False(control.IsHandleCreated); + } + + [Theory] + [InlineData(TabAlignment.Top, false)] + [InlineData(TabAlignment.Bottom, false)] + [InlineData(TabAlignment.Left, true)] + [InlineData(TabAlignment.Right, true)] + public void TabControl_Alignment_Set_GetReturnsExpected(TabAlignment value, bool expectedMultiline) + { + var control = new TabControl + { + Alignment = value + }; + Assert.Equal(value, control.Alignment); + Assert.Equal(expectedMultiline, control.Multiline); + + // Set same. + control.Alignment = value; + Assert.Equal(value, control.Alignment); + Assert.Equal(expectedMultiline, control.Multiline); + } + + [Theory] + [InlineData(TabAlignment.Bottom, false)] + [InlineData(TabAlignment.Left, true)] + [InlineData(TabAlignment.Right, true)] + public void TabControl_Alignment_SetWithHandle_GetReturnsExpected(TabAlignment value, bool expectedMultiline) + { + var control = new TabControl(); + IntPtr oldHandle = control.Handle; + Assert.NotEqual(IntPtr.Zero, oldHandle); + + control.Alignment = value; + Assert.Equal(value, control.Alignment); + Assert.Equal(expectedMultiline, control.Multiline); + IntPtr newHandle = control.Handle; + Assert.NotEqual(IntPtr.Zero, newHandle); + Assert.NotEqual(oldHandle, newHandle); + + // Set same. + control.Alignment = value; + Assert.Equal(value, control.Alignment); + Assert.Equal(expectedMultiline, control.Multiline); + Assert.Equal(newHandle, control.Handle); + } + + [Theory] + [CommonMemberData(nameof(CommonTestHelper.GetEnumTypeTheoryDataInvalid), typeof(TabAlignment))] + public void TabControl_Alignment_SetInvalidValue_ThrowsInvalidEnumArgumentException(TabAlignment value) + { + var control = new TabControl(); + Assert.Throws("value", () => control.Alignment = value); + } + + [Theory] + [InlineData(TabAlignment.Bottom)] + [InlineData(TabAlignment.Left)] + [InlineData(TabAlignment.Right)] + public void TabControl_Appearance_GetFlatButtonsWithAlignment_ReturnsExpected(TabAlignment alignment) + { + var control = new TabControl + { + Appearance = TabAppearance.FlatButtons, + Alignment = alignment + }; + Assert.Equal(TabAppearance.Buttons, control.Appearance); + Assert.Equal(alignment, control.Alignment); + + control.Alignment = TabAlignment.Top; + Assert.Equal(TabAppearance.FlatButtons, control.Appearance); + Assert.Equal(TabAlignment.Top, control.Alignment); + } + + [Theory] + [CommonMemberData(nameof(CommonTestHelper.GetEnumTypeTheoryData), typeof(TabAppearance))] + public void TabControl_Appearance_Set_GetReturnsExpected(TabAppearance value) + { + var control = new TabControl + { + Appearance = value + }; + Assert.Equal(value, control.Appearance); + + // Set same. + control.Appearance = value; + Assert.Equal(value, control.Appearance); + } + + [Theory] + [InlineData(TabAppearance.Buttons)] + [InlineData(TabAppearance.FlatButtons)] + public void TabControl_Appearance_SetWithHandle_GetReturnsExpected(TabAppearance value) + { + var control = new TabControl(); + IntPtr oldHandle = control.Handle; + Assert.NotEqual(IntPtr.Zero, oldHandle); + + control.Appearance = value; + Assert.Equal(value, control.Appearance); + IntPtr newHandle = control.Handle; + Assert.NotEqual(IntPtr.Zero, newHandle); + Assert.NotEqual(oldHandle, newHandle); + + // Set same. + control.Appearance = value; + Assert.Equal(value, control.Appearance); + Assert.Equal(newHandle, control.Handle); + } + + [Theory] + [CommonMemberData(nameof(CommonTestHelper.GetEnumTypeTheoryDataInvalid), typeof(TabAppearance))] + public void TabControl_Appearance_SetInvalidValue_ThrowsInvalidEnumArgumentException(TabAppearance value) + { + var control = new TabControl(); + Assert.Throws("value", () => control.Appearance = value); + } + + [Fact] + public void TabControl_DisplayRectangle_Get_ReturnsExpectedAndCreatesHandle() + { + var control = new TabControl(); + Rectangle displayRectangle = control.DisplayRectangle; + Assert.True(displayRectangle.X >= 0); + Assert.True(displayRectangle.Y >= 0); + Assert.Equal(200 - displayRectangle.X * 2, control.DisplayRectangle.Width); + Assert.Equal(100 - displayRectangle.Y * 2, control.DisplayRectangle.Height); + Assert.True(control.IsHandleCreated); + Assert.Equal(displayRectangle, control.DisplayRectangle); + } + + [Fact] + public void TabControl_RowCount_Get_ReturnsExpectedAndCreatesHandle() + { + var control = new TabControl(); + Assert.Equal(0, control.RowCount); + Assert.True(control.IsHandleCreated); + } + + [Fact] + public void TabControl_SelectedIndex_GetWithHandle_ReturnsExpected() + { + var control = new TabControl(); + Assert.NotEqual(IntPtr.Zero, control.Handle); + Assert.Equal(-1, control.SelectedIndex); + } + + public class SubTabControl : TabControl + { + public new bool CanRaiseEvents => base.CanRaiseEvents; + + public new CreateParams CreateParams => base.CreateParams; + + public new Cursor DefaultCursor => base.DefaultCursor; + + public new ImeMode DefaultImeMode => base.DefaultImeMode; + + public new Padding DefaultMargin => base.DefaultMargin; + + public new Size DefaultMaximumSize => base.DefaultMaximumSize; + + public new Size DefaultMinimumSize => base.DefaultMinimumSize; + + public new Padding DefaultPadding => base.DefaultPadding; + + public new Size DefaultSize => base.DefaultSize; + + public new bool DesignMode => base.DesignMode; + + public new bool DoubleBuffered => base.DoubleBuffered; + + public new EventHandlerList Events => base.Events; + + public new ImeMode ImeModeBase => base.ImeModeBase; + } + } +} diff --git a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/TabPageTests.cs b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/TabPageTests.cs new file mode 100644 index 00000000000..861be6d55d4 --- /dev/null +++ b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/TabPageTests.cs @@ -0,0 +1,887 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Drawing; +using Moq; +using WinForms.Common.Tests; +using Xunit; + +namespace System.Windows.Forms.Tests +{ + public class TabPageTests + { + [Fact] + public void TabPage_Ctor_Default() + { + var page = new SubTabPage(); + Assert.False(page.AllowDrop); + Assert.Equal(AnchorStyles.Top | AnchorStyles.Left, page.Anchor); + Assert.False(page.AutoScroll); + Assert.Equal(Size.Empty, page.AutoScrollMargin); + Assert.Equal(Size.Empty, page.AutoScrollMinSize); + Assert.Equal(Point.Empty, page.AutoScrollPosition); + Assert.False(page.AutoSize); + Assert.Equal(AutoSizeMode.GrowOnly, page.AutoSizeMode); + Assert.Equal(Control.DefaultBackColor, page.BackColor); + Assert.Null(page.BackgroundImage); + Assert.Equal(ImageLayout.Tile, page.BackgroundImageLayout); + Assert.Null(page.BindingContext); + Assert.Equal(BorderStyle.None, page.BorderStyle); + Assert.Equal(100, page.Bottom); + Assert.Equal(new Rectangle(0, 0, 200, 100), page.Bounds); + Assert.True(page.CanRaiseEvents); + Assert.Equal(new Rectangle(0, 0, 200, 100), page.ClientRectangle); + Assert.Equal(new Size(200, 100), page.ClientSize); + Assert.Null(page.Container); + Assert.True(page.CausesValidation); + Assert.Empty(page.Controls); + Assert.Same(page.Controls, page.Controls); + Assert.IsType(page.Controls); + Assert.False(page.Created); + Assert.Same(Cursors.Default, page.Cursor); + Assert.Same(Cursors.Default, page.DefaultCursor); + Assert.Equal(ImeMode.Inherit, page.DefaultImeMode); + Assert.Equal(new Padding(3), page.DefaultMargin); + Assert.Equal(Size.Empty, page.DefaultMaximumSize); + Assert.Equal(Size.Empty, page.DefaultMinimumSize); + Assert.Equal(Padding.Empty, page.DefaultPadding); + Assert.Equal(new Size(200, 100), page.DefaultSize); + Assert.False(page.DesignMode); + Assert.Equal(new Rectangle(0, 0, 200, 100), page.DisplayRectangle); + Assert.Equal(DockStyle.None, page.Dock); + Assert.NotNull(page.DockPadding); + Assert.Same(page.DockPadding, page.DockPadding); + Assert.Equal(0, page.DockPadding.Top); + Assert.Equal(0, page.DockPadding.Bottom); + Assert.Equal(0, page.DockPadding.Left); + Assert.Equal(0, page.DockPadding.Right); + Assert.False(page.DoubleBuffered); + Assert.True(page.Enabled); + Assert.NotNull(page.Events); + Assert.Same(page.Events, page.Events); + Assert.Equal(Control.DefaultFont, page.Font); + Assert.Equal(Control.DefaultForeColor, page.ForeColor); + Assert.False(page.HasChildren); + Assert.Equal(100, page.Height); + Assert.NotNull(page.HorizontalScroll); + Assert.Same(page.HorizontalScroll, page.HorizontalScroll); + Assert.False(page.HScroll); + Assert.Equal(ImeMode.NoControl, page.ImeMode); + Assert.Equal(ImeMode.NoControl, page.ImeModeBase); + Assert.Equal(0, page.Left); + Assert.Equal(Point.Empty, page.Location); + Assert.Equal(Padding.Empty, page.Padding); + Assert.Equal(200, page.Right); + Assert.Equal(RightToLeft.No, page.RightToLeft); + Assert.Equal(new Size(200, 100), page.Size); + Assert.Equal(0, page.TabIndex); + Assert.False(page.TabStop); + Assert.Empty(page.Text); + Assert.Equal(0, page.Top); + Assert.False(page.UseVisualStyleBackColor); + Assert.True(page.Visible); + Assert.NotNull(page.VerticalScroll); + Assert.Same(page.VerticalScroll, page.VerticalScroll); + Assert.False(page.VScroll); + Assert.Equal(200, page.Width); + } + + [Theory] + [MemberData(nameof(ControlTests.Anchor_Set_TestData), MemberType = typeof(ControlTests))] + public void TabPage_Anchor_Set_GetReturnsExpected(AnchorStyles value, AnchorStyles expected) + { + var control = new TabPage + { + Anchor = value + }; + Assert.Equal(expected, control.Anchor); + Assert.Equal(DockStyle.None, control.Dock); + + // Set same. + control.Anchor = value; + Assert.Equal(expected, control.Anchor); + Assert.Equal(DockStyle.None, control.Dock); + } + + [Theory] + [MemberData(nameof(ControlTests.Anchor_Set_TestData), MemberType = typeof(ControlTests))] + public void TabPage_Anchor_SetWithOldValue_GetReturnsExpected(AnchorStyles value, AnchorStyles expected) + { + var control = new TabPage + { + Anchor = AnchorStyles.Left + }; + + control.Anchor = value; + Assert.Equal(expected, control.Anchor); + Assert.Equal(DockStyle.None, control.Dock); + + // Set same. + control.Anchor = value; + Assert.Equal(expected, control.Anchor); + Assert.Equal(DockStyle.None, control.Dock); + } + + [Theory] + [MemberData(nameof(ControlTests.Anchor_SetWithDock_TestData), MemberType = typeof(ControlTests))] + public void TabPage_Anchor_SetWithDock_GetReturnsExpected(DockStyle dock, AnchorStyles value, AnchorStyles expectedAnchor, DockStyle expectedDock) + { + var control = new TabPage + { + Dock = dock + }; + + control.Anchor = value; + Assert.Equal(expectedAnchor, control.Anchor); + Assert.Equal(expectedDock, control.Dock); + + // Set same. + control.Anchor = value; + Assert.Equal(expectedAnchor, control.Anchor); + Assert.Equal(expectedDock, control.Dock); + } + + [Theory] + [CommonMemberData(nameof(CommonTestHelper.GetBoolTheoryData))] + public void TabPage_AutoSize_Set_GetReturnsExpected(bool value) + { + var control = new TabPage + { + AutoSize = value + }; + Assert.Equal(value, control.AutoSize); + + // Set same. + control.AutoSize = value; + Assert.Equal(value, control.AutoSize); + + // Set different. + control.AutoSize = value; + Assert.Equal(value, control.AutoSize); + } + + [Fact] + public void TabPage_AutoSize_SetWithHandler_CallsAutoSizeChanged() + { + var control = new TabPage + { + AutoSize = true + }; + int callCount = 0; + EventHandler handler = (sender, e) => + { + Assert.Same(control, sender); + Assert.Same(EventArgs.Empty, e); + callCount++; + }; + control.AutoSizeChanged += handler; + + // Set different. + control.AutoSize = false; + Assert.False(control.AutoSize); + Assert.Equal(1, callCount); + + // Set same. + control.AutoSize = false; + Assert.False(control.AutoSize); + Assert.Equal(1, callCount); + + // Set different. + control.AutoSize = true; + Assert.True(control.AutoSize); + Assert.Equal(2, callCount); + + // Remove handler. + control.AutoSizeChanged -= handler; + control.AutoSize = false; + Assert.False(control.AutoSize); + Assert.Equal(2, callCount); + } + + [Theory] + [CommonMemberData(nameof(CommonTestHelper.GetEnumTypeTheoryData), typeof(AutoSizeMode))] + public void TabPage_AutoSizeMode_Set_GetReturnsExpected(AutoSizeMode value) + { + var page = new TabPage + { + AutoSizeMode = value + }; + Assert.Equal(AutoSizeMode.GrowOnly, page.AutoSizeMode); + + // Set same. + page.AutoSizeMode = value; + Assert.Equal(AutoSizeMode.GrowOnly, page.AutoSizeMode); + } + + [Theory] + [CommonMemberData(nameof(CommonTestHelper.GetEnumTypeTheoryData), typeof(AutoSizeMode))] + [CommonMemberData(nameof(CommonTestHelper.GetEnumTypeTheoryDataInvalid), typeof(AutoSizeMode))] + public void TabPage_AutoSizeMode_SetWithParent_GetReturnsExpected(AutoSizeMode value) + { + var parent = new TabControl(); + var page = new TabPage + { + Parent = parent, + AutoSizeMode = value + }; + Assert.Equal(AutoSizeMode.GrowOnly, page.AutoSizeMode); + + // Set same. + page.AutoSizeMode = value; + Assert.Equal(AutoSizeMode.GrowOnly, page.AutoSizeMode); + } + + public static IEnumerable BackColor_Get_TestData() + { + yield return new object[] { true, null, Control.DefaultBackColor }; + yield return new object[] { false, null, Control.DefaultBackColor }; + + yield return new object[] { true, new TabControl { Appearance = TabAppearance.Normal }, Color.Transparent }; + yield return new object[] { false, new TabControl { Appearance = TabAppearance.Normal }, Control.DefaultBackColor }; + + yield return new object[] { true, new TabControl { Appearance = TabAppearance.Buttons }, Control.DefaultBackColor }; + yield return new object[] { false, new TabControl { Appearance = TabAppearance.Buttons }, Control.DefaultBackColor }; + + yield return new object[] { true, new TabControl { Appearance = TabAppearance.FlatButtons }, Control.DefaultBackColor }; + yield return new object[] { false, new TabControl { Appearance = TabAppearance.FlatButtons }, Control.DefaultBackColor }; + } + + [Theory] + [MemberData(nameof(BackColor_Get_TestData))] + public void TabPage_BackColor_GetWithParent_ReturnsExpected(bool useVisualStyleBackColor, TabControl parent, Color expected) + { + if (!Application.RenderWithVisualStyles) + { + return; + } + var page = new TabPage + { + UseVisualStyleBackColor = useVisualStyleBackColor, + Parent = parent + }; + Assert.Equal(expected, page.BackColor); + } + + [Theory] + [CommonMemberData(nameof(CommonTestHelper.GetBackColorTheoryData))] + public void TabPage_BackColor_Set_GetReturnsExpected(Color value, Color expected) + { + var control = new TabPage + { + BackColor = value + }; + Assert.Equal(expected, control.BackColor); + Assert.False(control.UseVisualStyleBackColor); + + // Set same. + control.BackColor = value; + Assert.Equal(expected, control.BackColor); + Assert.False(control.UseVisualStyleBackColor); + } + + [Theory] + [CommonMemberData(nameof(CommonTestHelper.GetBackColorTheoryData))] + public void TabPage_BackColor_SetWithUseVisualStyleBackColor_GetReturnsExpected(Color value, Color expected) + { + var control = new TabPage + { + UseVisualStyleBackColor = true, + BackColor = value + }; + Assert.Equal(expected, control.BackColor); + Assert.False(control.UseVisualStyleBackColor); + + // Set same. + control.BackColor = value; + Assert.Equal(expected, control.BackColor); + Assert.False(control.UseVisualStyleBackColor); + } + + [Theory] + [CommonMemberData(nameof(CommonTestHelper.GetBackColorTheoryData))] + public void TabPage_BackColor_SetDesignMode_GetReturnsExpected(Color value, Color expected) + { + var mockSite = new Mock(MockBehavior.Strict); + mockSite + .Setup(s => s.GetService(typeof(AmbientProperties))) + .Returns(null); + mockSite + .Setup(s => s.GetService(typeof(IDictionaryService))) + .Returns(null); + mockSite + .Setup(s => s.GetService(typeof(IExtenderListService))) + .Returns(null); + mockSite + .Setup(s => s.GetService(typeof(IComponentChangeService))) + .Returns(null); + mockSite + .Setup(s => s.GetService(typeof(ITypeDescriptorFilterService))) + .Returns(null); + mockSite + .Setup(s => s.DesignMode) + .Returns(true); + var control = new TabPage + { + Site = mockSite.Object, + BackColor = value + }; + Assert.Equal(expected, control.BackColor); + Assert.False(control.UseVisualStyleBackColor); + + // Set same. + control.BackColor = value; + Assert.Equal(expected, control.BackColor); + Assert.False(control.UseVisualStyleBackColor); + } + + [Fact] + public void TabPage_BackColor_SetWithHandler_CallsBackColorChanged() + { + var control = new TabPage(); + int callCount = 0; + EventHandler handler = (sender, e) => + { + Assert.Same(control, sender); + Assert.Same(EventArgs.Empty, e); + callCount++; + }; + control.BackColorChanged += handler; + + // Set different. + control.BackColor = Color.Red; + Assert.Equal(Color.Red, control.BackColor); + Assert.Equal(1, callCount); + + // Set same. + control.BackColor = Color.Red; + Assert.Equal(Color.Red, control.BackColor); + Assert.Equal(1, callCount); + + // Set different. + control.BackColor = Color.Empty; + Assert.Equal(Control.DefaultBackColor, control.BackColor); + Assert.Equal(2, callCount); + + // Remove handler. + control.BackColorChanged -= handler; + control.BackColor = Color.Red; + Assert.Equal(Color.Red, control.BackColor); + Assert.Equal(2, callCount); + } + + [Theory] + [CommonMemberData(nameof(CommonTestHelper.GetEnumTypeTheoryData), typeof(DockStyle))] + public void TabPage_Dock_Set_GetReturnsExpected(DockStyle value) + { + var control = new TabPage + { + Dock = value + }; + Assert.Equal(value, control.Dock); + Assert.Equal(AnchorStyles.Top | AnchorStyles.Left, control.Anchor); + + // Set same. + control.Dock = value; + Assert.Equal(value, control.Dock); + Assert.Equal(AnchorStyles.Top | AnchorStyles.Left, control.Anchor); + } + + [Theory] + [CommonMemberData(nameof(CommonTestHelper.GetEnumTypeTheoryData), typeof(DockStyle))] + public void TabPage_Dock_SetWithOldValue_GetReturnsExpected(DockStyle value) + { + var control = new TabPage + { + Dock = DockStyle.Top + }; + + control.Dock = value; + Assert.Equal(value, control.Dock); + Assert.Equal(AnchorStyles.Top | AnchorStyles.Left, control.Anchor); + + // Set same. + control.Dock = value; + Assert.Equal(value, control.Dock); + Assert.Equal(AnchorStyles.Top | AnchorStyles.Left, control.Anchor); + } + + [Theory] + [MemberData(nameof(ControlTests.Dock_SetWithAnchor_TestData), MemberType = typeof(ControlTests))] + public void TabPage_Dock_SetWithAnchor_GetReturnsExpected(AnchorStyles anchor, DockStyle value, AnchorStyles expectedAnchor) + { + var control = new TabPage + { + Anchor = anchor + }; + + control.Dock = value; + Assert.Equal(value, control.Dock); + Assert.Equal(expectedAnchor, control.Anchor); + + // Set same. + control.Dock = value; + Assert.Equal(value, control.Dock); + Assert.Equal(expectedAnchor, control.Anchor); + } + + [Fact] + public void TabPage_Dock_SetWithHandler_CallsDockChanged() + { + var control = new TabPage(); + int callCount = 0; + EventHandler handler = (sender, e) => + { + Assert.Same(control, sender); + Assert.Same(EventArgs.Empty, e); + callCount++; + }; + control.DockChanged += handler; + + // Set different. + control.Dock = DockStyle.Top; + Assert.Equal(DockStyle.Top, control.Dock); + Assert.Equal(1, callCount); + + // Set same. + control.Dock = DockStyle.Top; + Assert.Equal(DockStyle.Top, control.Dock); + Assert.Equal(1, callCount); + + // Set different. + control.Dock = DockStyle.Left; + Assert.Equal(DockStyle.Left, control.Dock); + Assert.Equal(2, callCount); + + // Remove handler. + control.DockChanged -= handler; + control.Dock = DockStyle.Top; + Assert.Equal(DockStyle.Top, control.Dock); + Assert.Equal(2, callCount); + } + + [Theory] + [CommonMemberData(nameof(CommonTestHelper.GetEnumTypeTheoryDataInvalid), typeof(DockStyle))] + public void TabPage_Dock_SetInvalid_ThrowsInvalidEnumArgumentException(DockStyle value) + { + var control = new TabPage(); + Assert.Throws("value", () => control.Dock = value); + } + + [Theory] + [CommonMemberData(nameof(CommonTestHelper.GetBoolTheoryData))] + public void TabPage_Enabled_Set_GetReturnsExpected(bool value) + { + var control = new TabPage + { + Enabled = value + }; + Assert.Equal(value, control.Enabled); + + // Set same. + control.Enabled = value; + Assert.Equal(value, control.Enabled); + + // Set different. + control.Enabled = value; + Assert.Equal(value, control.Enabled); + } + + [Theory] + [CommonMemberData(nameof(CommonTestHelper.GetBoolTheoryData))] + public void TabPage_Enabled_SetWithHandle_GetReturnsExpected(bool value) + { + var control = new TabPage(); + Assert.NotEqual(IntPtr.Zero, control.Handle); + + control.Enabled = value; + Assert.Equal(value, control.Enabled); + + // Set same. + control.Enabled = value; + Assert.Equal(value, control.Enabled); + + // Set different. + control.Enabled = value; + Assert.Equal(value, control.Enabled); + } + + [Fact] + public void TabPage_Enabled_SetWithHandler_CallsEnabledChanged() + { + var control = new TabPage + { + Enabled = true + }; + int callCount = 0; + EventHandler handler = (sender, e) => + { + Assert.Same(control, sender); + Assert.Same(EventArgs.Empty, e); + callCount++; + }; + control.EnabledChanged += handler; + + // Set different. + control.Enabled = false; + Assert.False(control.Enabled); + Assert.Equal(1, callCount); + + // Set same. + control.Enabled = false; + Assert.False(control.Enabled); + Assert.Equal(1, callCount); + + // Set different. + control.Enabled = true; + Assert.True(control.Enabled); + Assert.Equal(2, callCount); + + // Remove handler. + control.EnabledChanged -= handler; + control.Enabled = false; + Assert.False(control.Enabled); + Assert.Equal(2, callCount); + } + + [Theory] + [CommonMemberData(nameof(CommonTestHelper.GetPointTheoryData))] + public void TabPage_Location_Set_GetReturnsExpected(Point value) + { + var control = new TabPage + { + Location = value + }; + Assert.Equal(value, control.Location); + + // Set same. + control.Location = value; + Assert.Equal(value, control.Location); + } + + [Theory] + [CommonMemberData(nameof(CommonTestHelper.GetPointTheoryData))] + public void TabPage_Location_SetWithParent_GetReturnsExpected(Point value) + { + var parent = new TabControl(); + var control = new TabPage + { + Parent = parent, + Location = value + }; + Assert.Equal(value, control.Location); + + // Set same. + control.Location = value; + Assert.Equal(value, control.Location); + } + + [Fact] + public void TabPage_Location_SetWithHandle_DoesNotCallInvalidate() + { + var control = new TabPage(); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + + // Set different. + control.Location = new Point(1, 2); + Assert.Equal(new Point(1, 2), control.Location); + Assert.Equal(0, invalidatedCallCount); + + // Set same. + control.Location = new Point(1, 2); + Assert.Equal(new Point(1, 2), control.Location); + Assert.Equal(0, invalidatedCallCount); + + // Set different. + control.Location = new Point(2, 3); + Assert.Equal(new Point(2, 3), control.Location); + Assert.Equal(0, invalidatedCallCount); + } + + [Theory] + [InlineData(true, 1)] + [InlineData(false, 0)] + public void TabPage_Location_SetWithHandleWithTransparentBackColor_DoesNotCallInvalidate(bool supportsTransparentBackgroundColor, int expectedInvalidatedCallCount) + { + var control = new SubTabPage(); + control.SetStyle(ControlStyles.SupportsTransparentBackColor, true); + control.BackColor = Color.FromArgb(254, 255, 255, 255); + control.SetStyle(ControlStyles.SupportsTransparentBackColor, supportsTransparentBackgroundColor); + + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + + // Set different. + control.Location = new Point(1, 2); + Assert.Equal(new Point(1, 2), control.Location); + Assert.Equal(expectedInvalidatedCallCount, invalidatedCallCount); + + // Set same. + control.Location = new Point(1, 2); + Assert.Equal(new Point(1, 2), control.Location); + Assert.Equal(expectedInvalidatedCallCount, invalidatedCallCount); + + // Set different. + control.Location = new Point(2, 3); + Assert.Equal(new Point(2, 3), control.Location); + Assert.Equal(expectedInvalidatedCallCount * 2, invalidatedCallCount); + } + + [Fact] + public void TabPage_Location_SetWithHandler_CallsLocationChanged() + { + var control = new TabPage(); + int locationChangedCallCount = 0; + EventHandler locationChangedHandler = (sender, e) => + { + Assert.Same(control, sender); + Assert.Same(EventArgs.Empty, e); + locationChangedCallCount++; + }; + control.LocationChanged += locationChangedHandler; + int moveCallCount = 0; + EventHandler moveHandler = (sender, e) => + { + Assert.Same(control, sender); + Assert.Same(EventArgs.Empty, e); + moveCallCount++; + }; + control.Move += moveHandler; + + // Set different. + control.Location = new Point(1, 2); + Assert.Equal(new Point(1, 2), control.Location); + Assert.Equal(1, locationChangedCallCount); + Assert.Equal(1, moveCallCount); + + // Set same. + control.Location = new Point(1, 2); + Assert.Equal(new Point(1, 2), control.Location); + Assert.Equal(1, locationChangedCallCount); + Assert.Equal(1, moveCallCount); + + // Set different x. + control.Location = new Point(2, 2); + Assert.Equal(new Point(2, 2), control.Location); + Assert.Equal(2, locationChangedCallCount); + Assert.Equal(2, moveCallCount); + + // Set different y. + control.Location = new Point(2, 3); + Assert.Equal(new Point(2, 3), control.Location); + Assert.Equal(3, locationChangedCallCount); + Assert.Equal(3, moveCallCount); + + // Remove handler. + control.LocationChanged -= locationChangedHandler; + control.Move -= moveHandler; + control.Location = new Point(1, 2); + Assert.Equal(new Point(1, 2), control.Location); + Assert.Equal(3, locationChangedCallCount); + Assert.Equal(3, moveCallCount); + } + + public static IEnumerable Parent_Set_TestData() + { + yield return new object[] { null }; + yield return new object[] { new TabControl() }; + } + + [Theory] + [MemberData(nameof(Parent_Set_TestData))] + public void TabPage_Parent_Set_GetReturnsExpected(Control value) + { + var control = new TabPage + { + Parent = value + }; + Assert.Same(value, control.Parent); + + // Set same. + control.Parent = value; + Assert.Same(value, control.Parent); + } + + [Theory] + [MemberData(nameof(Parent_Set_TestData))] + public void TabPage_Parent_SetWithNonNullOldParent_GetReturnsExpected(Control value) + { + var oldParent = new TabControl(); + var control = new TabPage + { + Parent = oldParent + }; + + control.Parent = value; + Assert.Same(value, control.Parent); + Assert.Empty(oldParent.Controls); + + // Set same. + control.Parent = value; + Assert.Same(value, control.Parent); + Assert.Empty(oldParent.Controls); + } + + [Fact] + public void TabPage_Parent_SetNonNull_AddsToControls() + { + var parent = new TabControl(); + var control = new TabPage + { + Parent = parent + }; + Assert.Same(parent, control.Parent); + Assert.Same(control, Assert.Single(parent.Controls)); + + // Set same. + control.Parent = parent; + Assert.Same(parent, control.Parent); + Assert.Same(control, Assert.Single(parent.Controls)); + } + + [Fact] + public void TabPage_Parent_SetWithHandler_CallsParentChanged() + { + var parent = new TabControl(); + var control = new TabPage(); + int callCount = 0; + EventHandler handler = (sender, e) => + { + Assert.Same(control, sender); + Assert.Same(EventArgs.Empty, e); + callCount++; + }; + control.ParentChanged += handler; + + // Set different. + control.Parent = parent; + Assert.Same(parent, control.Parent); + Assert.Equal(1, callCount); + + // Set same. + control.Parent = parent; + Assert.Same(parent, control.Parent); + Assert.Equal(1, callCount); + + // Set null. + control.Parent = null; + Assert.Null(control.Parent); + Assert.Equal(2, callCount); + + // Remove handler. + control.ParentChanged -= handler; + control.Parent = parent; + Assert.Same(parent, control.Parent); + Assert.Equal(2, callCount); + } + + [Fact] + public void TabPage_Parent_SetSame_ThrowsArgumentException() + { + var control = new TabPage(); + Assert.Throws(null, () => control.Parent = control); + Assert.Null(control.Parent); + } + + [Theory] + [CommonMemberData(nameof(CommonTestHelper.GetBoolTheoryData))] + public void TabPage_UseVisualStyleBackColor_Set_GetReturnsExpected(bool value) + { + var tabPage = new TabPage + { + UseVisualStyleBackColor = value + }; + Assert.Equal(value, tabPage.UseVisualStyleBackColor); + + // Set same. + tabPage.UseVisualStyleBackColor = value; + Assert.Equal(value, tabPage.UseVisualStyleBackColor); + + // Set different. + tabPage.UseVisualStyleBackColor = !value; + Assert.Equal(!value, tabPage.UseVisualStyleBackColor); + } + + [Fact] + public void TabPage_UseVisualStyleBackColor_SetWithHandle_CallsInvalidate() + { + var tabPage = new TabPage(); + Assert.NotEqual(IntPtr.Zero, tabPage.Handle); + int invalidatedCallCount = 0; + tabPage.Invalidated += (sender, e) => invalidatedCallCount++; + + // Set different. + tabPage.UseVisualStyleBackColor = true; + Assert.True(tabPage.UseVisualStyleBackColor); + Assert.Equal(1, invalidatedCallCount); + + // Set same. + tabPage.UseVisualStyleBackColor = true; + Assert.True(tabPage.UseVisualStyleBackColor); + Assert.Equal(1, invalidatedCallCount); + + // Set different. + tabPage.UseVisualStyleBackColor = false; + Assert.False(tabPage.UseVisualStyleBackColor); + Assert.Equal(2, invalidatedCallCount); + } + + [Fact] + public void TabPage_ToString_Invoke_ReturnsExpected() + { + var page = new TabPage(); + Assert.Equal("TabPage: {}", page.ToString()); + } + + private class SubTabPage : TabPage + { + public new bool CanEnableIme => base.CanEnableIme; + + public new bool CanRaiseEvents => base.CanRaiseEvents; + + public new CreateParams CreateParams => base.CreateParams; + + public new Cursor DefaultCursor => base.DefaultCursor; + + public new ImeMode DefaultImeMode => base.DefaultImeMode; + + public new Padding DefaultMargin => base.DefaultMargin; + + public new Size DefaultMaximumSize => base.DefaultMaximumSize; + + public new Size DefaultMinimumSize => base.DefaultMinimumSize; + + public new Padding DefaultPadding => base.DefaultPadding; + + public new Size DefaultSize => base.DefaultSize; + + public new bool DesignMode => base.DesignMode; + + public new bool DoubleBuffered => base.DoubleBuffered; + + public new EventHandlerList Events => base.Events; + + public new ImeMode ImeModeBase => base.ImeModeBase; + + public new bool HScroll + { + get => base.HScroll; + set => base.HScroll = value; + } + + public new bool VScroll + { + get => base.VScroll; + set => base.VScroll = value; + } + + public new void SetStyle(ControlStyles flag, bool value) => base.SetStyle(flag, value); + } + } +} diff --git a/src/System.Windows.Forms/tests/UnitTests/TabControlTests.cs b/src/System.Windows.Forms/tests/UnitTests/TabControlTests.cs deleted file mode 100644 index 6dd866025fa..00000000000 --- a/src/System.Windows.Forms/tests/UnitTests/TabControlTests.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Xunit; - -namespace System.Windows.Forms.Tests -{ - public class TabControlTests - { - [Fact] - public void TabControlTest_Constructor() - { - var tc = new TabControl(); - - Assert.NotNull(tc); - Assert.NotNull(tc.TabPages); - } - } -}