diff --git a/src/System.Windows.Forms/src/PublicAPI.Unshipped.txt b/src/System.Windows.Forms/src/PublicAPI.Unshipped.txt index e69de29bb2d..e64813fe631 100644 --- a/src/System.Windows.Forms/src/PublicAPI.Unshipped.txt +++ b/src/System.Windows.Forms/src/PublicAPI.Unshipped.txt @@ -0,0 +1,11 @@ +override System.Windows.Forms.TabControl.OnGotFocus(System.EventArgs e) -> void +override System.Windows.Forms.TabControl.OnLostFocus(System.EventArgs e) -> void +override System.Windows.Forms.TabPage.OnGotFocus(System.EventArgs e) -> void +override System.Windows.Forms.TabPage.OnLostFocus(System.EventArgs e) -> void +virtual System.Windows.Forms.Control.SetToolTip(System.Windows.Forms.ToolTip toolTip, string toolTipText) -> void +override System.Windows.Forms.UpDownBase.SetToolTip(System.Windows.Forms.ToolTip toolTip, string toolTipText) -> void +override System.Windows.Forms.TabControl.SetToolTip(System.Windows.Forms.ToolTip toolTip, string toolTipText) -> void +override System.Windows.Forms.Label.SetToolTip(System.Windows.Forms.ToolTip toolTip, string toolTipText) -> void +override System.Windows.Forms.ListView.SetToolTip(System.Windows.Forms.ToolTip toolTip, string toolTipText) -> void +override System.Windows.Forms.TabPage.SetToolTip(System.Windows.Forms.ToolTip toolTip, string toolTipText) -> void +override System.Windows.Forms.TreeView.SetToolTip(System.Windows.Forms.ToolTip toolTip, string toolTipText) -> void \ No newline at end of file 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 4bd4464e465..55ad3f76884 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs @@ -10918,6 +10918,19 @@ internal static IntPtr SetUpPalette(IntPtr dc, bool force, bool realizePalette) return result; } + protected virtual void SetToolTip(ToolTip toolTip, string toolTipText) + { } + + internal void SetToolTipInternal(ToolTip toolTip, string toolTipText) + { + if (!IsHandleCreated || toolTip == null) + { + return; + } + + SetToolTip(toolTip, toolTipText); + } + protected void SetTopLevel(bool value) { if (value && IsActiveX) @@ -14149,9 +14162,11 @@ IList IKeyboardToolTip.GetNeighboringToolsRectangles() bool IKeyboardToolTip.IsHoveredWithMouse() { - return ClientRectangle.Contains(PointToClient(MousePosition)); + return IsHoveredWithMouse; } + private protected virtual bool IsHoveredWithMouse => ClientRectangle.Contains(PointToClient(MousePosition)); + bool IKeyboardToolTip.HasRtlModeEnabled() { Control topLevelControl = TopLevelControlInternal; diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/KeyboardToolTipStateMachine.cs b/src/System.Windows.Forms/src/System/Windows/Forms/KeyboardToolTipStateMachine.cs index cfce4d98a5c..8fb384c81ce 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/KeyboardToolTipStateMachine.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/KeyboardToolTipStateMachine.cs @@ -57,29 +57,47 @@ private KeyboardToolTipStateMachine() } private SmState Transition(IKeyboardToolTip tool, ToolTip tooltip, SmEvent @event) - => (_currentState, @event) switch + { + switch (_currentState, @event) { - (SmState.Hidden, SmEvent.FocusedTool) => SetupInitShowTimer(tool, tooltip), - (SmState.Hidden, SmEvent.LeftTool) => _currentState, // OK - (SmState.ReadyForInitShow, SmEvent.FocusedTool) => _currentState, // unlikely: focus without leave - (SmState.ReadyForInitShow, SmEvent.LeftTool) => FullFsmReset(), - (SmState.ReadyForInitShow, SmEvent.InitialDelayTimerExpired) => ShowToolTip(tool, tooltip), - - (SmState.Shown, SmEvent.FocusedTool) => _currentState, // unlikely: focus without leave - (SmState.Shown, SmEvent.LeftTool) => HideAndStartWaitingForRefocus(tool, tooltip), - (SmState.Shown, SmEvent.AutoPopupDelayTimerExpired) => FullFsmReset(), - - (SmState.WaitForRefocus, SmEvent.FocusedTool) => SetupReshowTimer(tool, tooltip), - (SmState.WaitForRefocus, SmEvent.LeftTool) => _currentState, // OK - (SmState.WaitForRefocus, SmEvent.RefocusWaitDelayExpired) => FullFsmReset(), - - (SmState.ReadyForReshow, SmEvent.FocusedTool) => _currentState, // unlikely: focus without leave - (SmState.ReadyForReshow, SmEvent.LeftTool) => StartWaitingForRefocus(tool), - (SmState.ReadyForReshow, SmEvent.ReshowDelayTimerExpired) => ShowToolTip(tool, tooltip), + case (SmState.Hidden, SmEvent.FocusedTool): + return SetupInitShowTimer(tool, tooltip); + case (SmState.Hidden, SmEvent.LeftTool): + return _currentState; // OK + + case (SmState.ReadyForInitShow, SmEvent.FocusedTool): + return _currentState; // unlikely: focus without leave + case (SmState.ReadyForInitShow, SmEvent.LeftTool): + return FullFsmReset(); + case (SmState.ReadyForInitShow, SmEvent.InitialDelayTimerExpired): + return ShowToolTip(tool, tooltip); + + case (SmState.Shown, SmEvent.FocusedTool): + return _currentState; // unlikely: focus without leave + case (SmState.Shown, SmEvent.LeftTool): + return HideAndStartWaitingForRefocus(tool, tooltip); + case (SmState.Shown, SmEvent.AutoPopupDelayTimerExpired): + return FullFsmReset(); + + case (SmState.WaitForRefocus, SmEvent.FocusedTool): + return SetupReshowTimer(tool, tooltip); + case (SmState.WaitForRefocus, SmEvent.LeftTool): + return _currentState; // OK + case (SmState.WaitForRefocus, SmEvent.RefocusWaitDelayExpired): + return FullFsmReset(); + + case (SmState.ReadyForReshow, SmEvent.FocusedTool): + return _currentState; // unlikely: focus without leave + case (SmState.ReadyForReshow, SmEvent.LeftTool): + return StartWaitingForRefocus(tool); + case (SmState.ReadyForReshow, SmEvent.ReshowDelayTimerExpired): + return ShowToolTip(tool, tooltip); // This is what we would have thrown historically - (_, _) => throw new KeyNotFoundException() - }; + default: + throw new KeyNotFoundException(); + } + } public void ResetStateMachine(ToolTip toolTip) { diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Label.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Label.cs index 0771878fa96..23679c68a88 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Label.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Label.cs @@ -1601,7 +1601,7 @@ private bool ShouldSerializeImage() /// /// Called by ToolTip to poke in that Tooltip into this ComCtl so that the Native ChildToolTip is not exposed. /// - internal void SetToolTip(ToolTip toolTip) + protected override void SetToolTip(ToolTip toolTip, string toolTipText) { if (toolTip != null && !controlToolTip) { diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/ListView.cs b/src/System.Windows.Forms/src/System/Windows/Forms/ListView.cs index aef7d3d4dac..bfb87e960ce 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/ListView.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/ListView.cs @@ -5072,9 +5072,14 @@ internal void UpdateSavedCheckedItems(ListViewItem item, bool addItem) /// /// Called by ToolTip to poke in that Tooltip into this ComCtl so that the Native ChildToolTip is not exposed. /// - internal void SetToolTip(ToolTip toolTip, string toolTipCaption) + protected override void SetToolTip(ToolTip toolTip, string toolTipText) { - this.toolTipCaption = toolTipCaption; + if (toolTip == null) + { + return; + } + + this.toolTipCaption = toolTipText; // native ListView expects tooltip HWND as a wParam and ignores lParam IntPtr oldHandle = User32.SendMessageW(this, (User32.WM)LVM.SETTOOLTIPS, toolTip.Handle, IntPtr.Zero); diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/TabControl.cs b/src/System.Windows.Forms/src/System/Windows/Forms/TabControl.cs index f18190b9e6e..58e47dcd3fb 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/TabControl.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/TabControl.cs @@ -1106,6 +1106,19 @@ internal TabPage GetTabPage(int index) return _tabPages[index]; } + internal Rectangle GetItemRectangle(int index) + { + if (index < 0 || index >= TabCount) + { + return Rectangle.Empty; + } + + RECT rectangle = new RECT(); + User32.SendMessageW(this, (User32.WM)ComCtl32.TCM.GETITEMRECT, (IntPtr)index, ref rectangle); + + return RectangleToScreen(rectangle); + } + /// /// This has package scope so that TabStrip and TabControl can call it. /// @@ -1360,6 +1373,20 @@ protected virtual void OnDrawItem(DrawItemEventArgs e) _onDrawItem?.Invoke(this, e); } + protected override void OnGotFocus(EventArgs e) + { + if (TabCount > 0 && SelectedTab != null) + { + KeyboardToolTipStateMachine.Instance.NotifyAboutGotFocus(SelectedTab); + } + else + { + KeyboardToolTipStateMachine.Instance.NotifyAboutGotFocus(this); + } + + base.OnGotFocus(e); + } + /// /// Actually goes and fires the OnLeave event. Inheriting controls /// should use this to know when the event is fired [this is preferable to @@ -1381,6 +1408,11 @@ protected override void OnEnter(EventArgs e) { SelectedTab.FireEnter(e); } + + if (TabCount == 0 && Enabled) + { + KeyboardToolTipStateMachine.Instance.NotifyAboutGotFocus(this); + } } /// @@ -1403,9 +1435,24 @@ protected override void OnLeave(EventArgs e) { SelectedTab.FireLeave(e); } + base.OnLeave(e); } + protected override void OnLostFocus(EventArgs e) + { + if (TabCount > 0 && SelectedTab != null) + { + KeyboardToolTipStateMachine.Instance.NotifyAboutLostFocus(SelectedTab); + } + else + { + KeyboardToolTipStateMachine.Instance.NotifyAboutLostFocus(this); + } + + base.OnLostFocus(e); + } + /// /// We override this to get tabbing functionality. /// If overriding this, remember to call base.onKeyDown. @@ -1484,6 +1531,11 @@ protected virtual void OnSelectedIndexChanged(EventArgs e) UpdateTabSelection(GetState(State.UISelection)); SetState(State.UISelection, false); _onSelectedIndexChanged?.Invoke(this, e); + + if (TabCount > 0 && SelectedTab != null) + { + KeyboardToolTipStateMachine.Instance.NotifyAboutGotFocus(SelectedTab); + } } /// @@ -1662,11 +1714,16 @@ private void ResizePages() /// /// Called by ToolTip to poke in that Tooltip into this ComCtl so that the Native ChildToolTip is not exposed. /// - internal void SetToolTip(ToolTip toolTip, string controlToolTipText) + protected override void SetToolTip(ToolTip toolTip, string toolTipText) { + if (toolTip == null || !ShowToolTips) + { + return; + } + User32.SendMessageW(this, (User32.WM)ComCtl32.TCM.SETTOOLTIPS, toolTip.Handle); GC.KeepAlive(toolTip); - _controlTipText = controlToolTipText; + _controlTipText = toolTipText; } private void SetTabPage(int index, TabPage value) 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 3830e963b05..82696ebc5e8 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/TabPage.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/TabPage.cs @@ -8,8 +8,10 @@ using System.Diagnostics; using System.Drawing; using System.Drawing.Design; +using System.Linq; using System.Runtime.InteropServices; using System.Windows.Forms.Layout; +using static Interop; namespace System.Windows.Forms { @@ -26,6 +28,11 @@ namespace System.Windows.Forms [DefaultProperty("Text")] public class TabPage : Panel { + /// + /// Internal property that has the default instance if is set. + /// This instance is replaced if an external ToolTip instance will be set. + /// + private ToolTip _toolTip; private ImageList.Indexer _imageIndexer; private string _toolTipText = string.Empty; private bool _enterFired = false; @@ -360,7 +367,7 @@ public string ToolTipText get => _toolTipText; set { - if (value == null) + if (string.IsNullOrWhiteSpace(value)) { value = string.Empty; } @@ -372,6 +379,28 @@ public string ToolTipText _toolTipText = value; UpdateParent(); + + ToolTip.SetToolTip(this, value); + KeyboardToolTipStateMachine.Instance.Hook(this, ToolTip); + } + } + + private protected override bool IsHoveredWithMouse + { + get + { + if (ParentInternal is TabControl tabControl) + { + for (int i = 0; i < tabControl.TabCount; i++) + { + if (tabControl.GetItemRectangle(i).Contains(MousePosition)) + { + return true; + } + } + } + + return ParentInternal.RectangleToScreen(ClientRectangle).Contains(MousePosition); } } @@ -442,6 +471,13 @@ internal void FireEnter(EventArgs e) OnEnter(e); } + protected override void OnGotFocus(EventArgs e) + { + KeyboardToolTipStateMachine.Instance.NotifyAboutGotFocus(this); + + base.OnGotFocus(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 @@ -464,6 +500,23 @@ protected override void OnEnter(EventArgs e) } } + internal override Rectangle GetToolNativeScreenRectangle() + { + // A tooltip will be shown near a selected tab + if (ParentInternal is TabControl tabControl) + { + return tabControl.GetItemRectangle(tabControl.SelectedIndex); + } + + return Rectangle.Empty; + } + + internal ToolTip ToolTip + { + get => _toolTip ??= new ToolTip(); + set => _toolTip = value; + } + /// /// 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 @@ -483,10 +536,18 @@ protected override void OnLeave(EventArgs e) base.OnLeave(e); } + KeyboardToolTipStateMachine.Instance.NotifyAboutLostFocus(this); _leaveFired = false; } } + protected override void OnLostFocus(EventArgs e) + { + KeyboardToolTipStateMachine.Instance.NotifyAboutLostFocus(this); + + base.OnLostFocus(e); + } + protected override void OnPaintBackground(PaintEventArgs e) { // Utilize the TabRenderer new to Whidbey to draw the tab pages so that the panels are @@ -542,6 +603,28 @@ protected override void SetBoundsCore(int x, int y, int width, int height, Bound } } + protected override void SetToolTip(ToolTip toolTip, string toolTipText) + { + if (toolTip == null) + { + return; + } + + // Check if there is an existing ToolTip object that is showing tooltips, + // if so - reset it to avoid showing several tooltips (old and new) at the same time. + if (ToolTip != toolTip) + { + ToolTip.SetToolTip(this, null); + ToolTip = toolTip; + } + + // Show the same tooltip for the page's tab. + if (toolTipText != null && ToolTipText != toolTipText) + { + ToolTipText = toolTipText; + } + } + /// /// Determines if the Location property needs to be persisted. /// diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/ToolTip.cs b/src/System.Windows.Forms/src/System/Windows/Forms/ToolTip.cs index 4448af7b2c4..1dadf78bef4 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/ToolTip.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/ToolTip.cs @@ -10,6 +10,7 @@ using System.Diagnostics; using System.Drawing; using System.Globalization; +using System.Reflection; using System.Runtime.InteropServices; using static Interop; using static Interop.ComCtl32; @@ -643,61 +644,29 @@ private void HandleCreated(object sender, EventArgs eventargs) Control control = (Control)sender; CreateRegion(control); - CheckNativeToolTip(control); - CheckCompositeControls(control); - + control?.SetToolTipInternal(this, GetToolTip(control)); KeyboardToolTipStateMachine.Instance.Hook(control, this); } - private void CheckNativeToolTip(Control associatedControl) + private void HandleDestroyed(object sender, EventArgs eventargs) { - // Wait for the Handle Creation. - if (!GetHandleCreated()) - { - return; - } - - if (associatedControl is TreeView treeView && treeView.ShowNodeToolTips) - { - treeView.SetToolTip(this, GetToolTip(associatedControl)); - } - - if (associatedControl is TabControl tabControl && tabControl.ShowToolTips) - { - tabControl.SetToolTip(this, GetToolTip(associatedControl)); - } - - if (associatedControl is ListView listView) - { - listView.SetToolTip(this, GetToolTip(associatedControl)); - } + Control control = (Control)sender; + DestroyRegion(control); - // Label now has its own Tooltip for AutoEllipsis. - // So this control too falls in special casing. - // We need to disable the LABEL AutoEllipsis tooltip and show - // this tooltip always. - if (associatedControl is Label label) - { - label.SetToolTip(this); - } + KeyboardToolTipStateMachine.Instance.Unhook(control, this); } - private void CheckCompositeControls(Control associatedControl) + /// + /// Handles LostFocus event of a set control + /// + private void OnControlLostFocus(object sender, EventArgs e) { - if (associatedControl is UpDownBase upDownBase) + if (sender is IWin32Window window) { - upDownBase.SetToolTip(this, GetToolTip(associatedControl)); + Hide(window); } } - private void HandleDestroyed(object sender, EventArgs eventargs) - { - Control control = (Control)sender; - DestroyRegion(control); - - KeyboardToolTipStateMachine.Instance.Unhook(control, this); - } - /// /// Fires the Draw event. /// @@ -1173,6 +1142,7 @@ public void RemoveAll() regions[i].HandleCreated -= new EventHandler(HandleCreated); regions[i].HandleDestroyed -= new EventHandler(HandleDestroyed); + regions[i].LostFocus -= OnControlLostFocus; KeyboardToolTipStateMachine.Instance.Unhook(regions[i], this); } @@ -1234,6 +1204,7 @@ private void SetToolTipInternal(Control control, TipInfo info) bool exists = _tools.ContainsKey(control); bool empty = info == null || string.IsNullOrEmpty(info.Caption); + if (exists && empty) { _tools.Remove(control); @@ -1247,6 +1218,7 @@ private void SetToolTipInternal(Control control, TipInfo info) { control.HandleCreated += new EventHandler(HandleCreated); control.HandleDestroyed += new EventHandler(HandleDestroyed); + control.LostFocus += OnControlLostFocus; if (control.IsHandleCreated) { @@ -1263,13 +1235,13 @@ private void SetToolTipInternal(Control control, TipInfo info) { ToolInfoWrapper toolInfo = GetTOOLINFO(control, info.Caption); toolInfo.SendMessage(this, (User32.WM)TTM.SETTOOLINFOW); - CheckNativeToolTip(control); - CheckCompositeControls(control); + control?.SetToolTipInternal(this, GetToolTip(control)); } else if (empty && exists && !DesignMode) { control.HandleCreated -= new EventHandler(HandleCreated); control.HandleDestroyed -= new EventHandler(HandleDestroyed); + control.LostFocus -= OnControlLostFocus; if (control.IsHandleCreated) { diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/TreeView.cs b/src/System.Windows.Forms/src/System/Windows/Forms/TreeView.cs index bbd59e820bb..48ba2bd7809 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/TreeView.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/TreeView.cs @@ -1701,14 +1701,16 @@ internal void ForceScrollbarUpdate(bool delayed) /// /// Called by ToolTip to poke in that Tooltip into this ComCtl so that the Native ChildToolTip is not exposed. /// - internal void SetToolTip(ToolTip toolTip, string toolTipText) + protected override void SetToolTip(ToolTip toolTip, string toolTipText) { - if (toolTip != null) + if (toolTip == null || !ShowNodeToolTips) { - User32.SendMessageW(toolTip, (User32.WM)TTM.SETMAXTIPWIDTH, IntPtr.Zero, (IntPtr)SystemInformation.MaxWindowTrackSize.Width); - User32.SendMessageW(this, (User32.WM)TVM.SETTOOLTIPS, toolTip.Handle); - controlToolTipText = toolTipText; + return; } + + User32.SendMessageW(toolTip, (User32.WM)TTM.SETMAXTIPWIDTH, IntPtr.Zero, (IntPtr)SystemInformation.MaxWindowTrackSize.Width); + User32.SendMessageW(this, (User32.WM)TVM.SETTOOLTIPS, toolTip.Handle); + controlToolTipText = toolTipText; } /// diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/UpDownBase.cs b/src/System.Windows.Forms/src/System/Windows/Forms/UpDownBase.cs index cb22c4e48c4..01e80dd6768 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/UpDownBase.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/UpDownBase.cs @@ -978,10 +978,18 @@ protected override void WndProc(ref Message m) } } - internal void SetToolTip(ToolTip toolTip, string caption) + /// + /// This Function sets the ToolTip for this composite control. + /// + protected override void SetToolTip(ToolTip toolTip, string toolTipText) { - toolTip.SetToolTip(_upDownEdit, caption); - toolTip.SetToolTip(_upDownButtons, caption); + if (toolTip == null) + { + return; + } + + toolTip.SetToolTip(_upDownEdit, toolTipText); + toolTip.SetToolTip(_upDownButtons, toolTipText); } } } diff --git a/src/System.Windows.Forms/tests/IntegrationTests/WinformsControlsTest/MainForm.Designer.cs b/src/System.Windows.Forms/tests/IntegrationTests/WinformsControlsTest/MainForm.Designer.cs index 3b8354de49d..0fca599845d 100644 --- a/src/System.Windows.Forms/tests/IntegrationTests/WinformsControlsTest/MainForm.Designer.cs +++ b/src/System.Windows.Forms/tests/IntegrationTests/WinformsControlsTest/MainForm.Designer.cs @@ -55,6 +55,7 @@ private void InitializeComponent() this.richTextBoxes = new System.Windows.Forms.Button(); this.PictureBoxes = new System.Windows.Forms.Button(); this.formBorderStyles = new System.Windows.Forms.Button(); + this.tabControl = new System.Windows.Forms.Button(); this.flowLayoutPanelUITypeEditors.SuspendLayout(); this.SuspendLayout(); // @@ -252,6 +253,7 @@ private void InitializeComponent() this.flowLayoutPanelUITypeEditors.Controls.Add(this.richTextBoxes); this.flowLayoutPanelUITypeEditors.Controls.Add(this.PictureBoxes); this.flowLayoutPanelUITypeEditors.Controls.Add(this.formBorderStyles); + this.flowLayoutPanelUITypeEditors.Controls.Add(this.tabControl); this.flowLayoutPanelUITypeEditors.Dock = System.Windows.Forms.DockStyle.Fill; this.flowLayoutPanelUITypeEditors.FlowDirection = System.Windows.Forms.FlowDirection.TopDown; this.flowLayoutPanelUITypeEditors.Location = new System.Drawing.Point(8, 8); @@ -309,6 +311,16 @@ private void InitializeComponent() this.formBorderStyles.UseVisualStyleBackColor = true; this.formBorderStyles.Click += new System.EventHandler(this.formBorderStyles_Click); // + // tabControl + // + this.tabControl.Location = new System.Drawing.Point(268, 293); + this.tabControl.Name = "tabControl"; + this.tabControl.Size = new System.Drawing.Size(258, 23); + this.tabControl.TabIndex = 21; + this.tabControl.Text = "TabControl"; + this.tabControl.UseVisualStyleBackColor = true; + this.tabControl.Click += new System.EventHandler(this.tabControlButton_Click); + // // MainForm // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); @@ -350,6 +362,7 @@ private void InitializeComponent() private System.Windows.Forms.Button richTextBoxes; private System.Windows.Forms.Button PictureBoxes; private System.Windows.Forms.Button formBorderStyles; + private System.Windows.Forms.Button tabControl; } } diff --git a/src/System.Windows.Forms/tests/IntegrationTests/WinformsControlsTest/MainForm.cs b/src/System.Windows.Forms/tests/IntegrationTests/WinformsControlsTest/MainForm.cs index 54af625fe31..aec9848f70e 100644 --- a/src/System.Windows.Forms/tests/IntegrationTests/WinformsControlsTest/MainForm.cs +++ b/src/System.Windows.Forms/tests/IntegrationTests/WinformsControlsTest/MainForm.cs @@ -132,5 +132,10 @@ private void formBorderStyles_Click(object sender, EventArgs e) { new FormBorderStyles().Show(); } + + private void tabControlButton_Click(object sender, EventArgs e) + { + new TabControlTest().Show(); + } } } diff --git a/src/System.Windows.Forms/tests/IntegrationTests/WinformsControlsTest/TabControlTest.Designer.cs b/src/System.Windows.Forms/tests/IntegrationTests/WinformsControlsTest/TabControlTest.Designer.cs new file mode 100644 index 00000000000..42abde0fe89 --- /dev/null +++ b/src/System.Windows.Forms/tests/IntegrationTests/WinformsControlsTest/TabControlTest.Designer.cs @@ -0,0 +1,153 @@ +// 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.Drawing; +using System.Windows.Forms; + +namespace WinformsControlsTest +{ + partial class TabControlTest + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + tabControl1 = new TabControl(); + tabPage1 = new TabPage(); + tabPage2 = new TabPage(); + toolTip = new ToolTip(); + button1 = new Button(); + button2 = new Button(); + button3 = new Button(); + internalButton = new Button(); + _label = new Label(); + tabControl1.SuspendLayout(); + SuspendLayout(); + // + // Set tooltip + // + //toolTip.SetToolTip(tabPage1, "Ultra super tabpage"); + + // + // Label + // + _label.Location = new Point(15, 180); + _label.MaximumSize = new Size(150, 18); + _label.AutoSize = true; + _label.Text = "Some label as.dkgfhas.dfkgjs/dakfgj/sdfkgj/alsdkfjg asdlfmas/dlkmf/asdkmf/askldf/sakdfaskgn"; + _label.AutoEllipsis = true; + + // + // button1 + // + button1.Location = new System.Drawing.Point(15, 140); + button1.Text = "Button1"; + button1.Click += ButtonClick; + toolTip.SetToolTip(button1, "Button1"); + // button2 + // + button2.Location = new System.Drawing.Point(100, 140); + button2.Text = "Button2"; + button2.Click += Button2Click; + toolTip.SetToolTip(button2, "Button2"); + // button3 + // + button3.Location = new System.Drawing.Point(185, 140); + button3.Text = "Button3"; + toolTip.SetToolTip(button3, "Button3"); + button3.Click += Button3Click; + // + // internalButton + // + tabPage1.Controls.Add(internalButton); + internalButton.Location = new System.Drawing.Point(15, 15); + internalButton.Size = new Size(100, 20); + internalButton.BackColor = Color.White; + internalButton.Text = "Internal button"; + toolTip.SetToolTip(internalButton, "Internal button"); + // + // tabControl1 + // + tabControl1.TabPages.Add(tabPage1); + tabControl1.TabPages.Add(tabPage2); + tabControl1.Location = new Point(15, 15); + tabControl1.Name = "tabControl1"; + tabControl1.SelectedIndex = 0; + tabControl1.Size = new Size(200, 100); + tabControl1.TabIndex = 0; + tabControl1.ShowToolTips = true; + // + // tabPage1 + // + tabPage1.Location = new System.Drawing.Point(4, 22); + tabPage1.Name = "tabPage1"; + tabPage1.Padding = new System.Windows.Forms.Padding(3); + tabPage1.Size = new System.Drawing.Size(20, 20); + tabPage1.TabIndex = 0; + tabPage1.Text = "tabPage1"; + //tabPage1.ToolTipText = "1_item"; + toolTip.SetToolTip(tabPage1, "1_item"); + + tabPage1.BackColor = Color.Red; + // + // tabPage2 + // + tabPage2.Location = new System.Drawing.Point(4, 22); + tabPage2.Name = "tabPage2"; + tabPage2.Padding = new System.Windows.Forms.Padding(3); + tabPage2.Size = new System.Drawing.Size(20, 20); + tabPage2.TabIndex = 0; + tabPage2.Text = "tabPage2"; + //tabPage2.ToolTipText = "2_item"; + toolTip.SetToolTip(tabPage2, "2_item"); + + tabPage2.UseVisualStyleBackColor = true; + // + // Form1 + // + AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + ClientSize = new System.Drawing.Size(343, 200); + Controls.Add(tabControl1); + Controls.Add(button1); + Controls.Add(button2); + Controls.Add(button3); + Controls.Add(_label); + Name = "Form1"; + Text = "Form1"; + tabControl1.ResumeLayout(false); + ResumeLayout(false); + } + + private TabControl tabControl1; + private TabPage tabPage1; + private TabPage tabPage2; + private Button button1; + private Button button2; + private Button button3; + private Button internalButton; + private ToolTip toolTip; + private Label _label; + } +} diff --git a/src/System.Windows.Forms/tests/IntegrationTests/WinformsControlsTest/TabControlTest.cs b/src/System.Windows.Forms/tests/IntegrationTests/WinformsControlsTest/TabControlTest.cs new file mode 100644 index 00000000000..ea5cbded358 --- /dev/null +++ b/src/System.Windows.Forms/tests/IntegrationTests/WinformsControlsTest/TabControlTest.cs @@ -0,0 +1,70 @@ +// 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; +using System.Globalization; +using System.Windows.Forms; + +namespace WinformsControlsTest +{ + public partial class TabControlTest : Form + { + public TabControlTest() + { + InitializeComponent(); + //toolTip.SetToolTip(tabControl1, "TabControl"); + } + + int i = -1; + + private void ButtonClick(object sender, EventArgs e) + { + // It will be removed after testing + switch (i) + { + case -1: + toolTip.SetToolTip(tabPage1, " \t \r\n "); + break; + case 0: + toolTip.SetToolTip(tabPage2, "This is page 2"); + break; + case 1: + toolTip.SetToolTip(tabPage1, "This is page 1"); + break; + case 2: + tabPage2.ToolTipText = "2) Some tt text"; + break; + case 3: + tabPage1.ToolTipText = "1) Some tt text"; + break; + } + + i++; + } + + int j = 0; + + private void Button2Click(object sender, EventArgs e) + { + new ToolTip().SetToolTip(internalButton, j.ToString()); + j++; + + new ToolTip().SetToolTip(_label, ""); + } + + private void Button3Click(object sender, EventArgs e) + { + new ToolTip().SetToolTip(_label, "New tooltip text"); + } + } + + public class MyLabel : Label + { + public MyLabel() + { + this.SetToolTip(new ToolTip(), "balas"); + //new ToolTip().SetToolTip(this, ""); + } + } +} 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 index c65c3fb0f00..76c536067f5 100644 --- a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/TabPageTests.cs +++ b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/TabPageTests.cs @@ -3062,6 +3062,42 @@ public void TabPage_Text_SetWithHandler_CallsTextChanged() Assert.Equal(2, callCount); } + [WinFormsFact] + public void TabPage_ToolTipText_SetCorrectToolTip() + { + using TabPage tabPage = new TabPage(); + tabPage.CreateControl(); + string expected = "Some text"; + tabPage.ToolTipText = expected; + string actual = tabPage.ToolTip.GetCaptionForTool(tabPage); + Assert.Equal(expected, actual); + } + + [WinFormsFact] + public void TabPage_SetNewToolTip_SetCorrectToolTipText() + { + using TabPage tabPage = new TabPage(); + tabPage.CreateControl(); + string expected = "Some text"; + using ToolTip toolTip = new ToolTip(); + toolTip.SetToolTip(tabPage, expected); + string actual = tabPage.ToolTipText; + Assert.Equal(expected, actual); + } + + [WinFormsFact] + public void TabPage_ToolTip_IsNotNull() + { + using TabPage tabPage = new TabPage(); + Assert.NotNull(tabPage.ToolTip); + + tabPage.ToolTip = new ToolTip(); + Assert.NotNull(tabPage.ToolTip); + + tabPage.ToolTip = null; + Assert.NotNull(tabPage.ToolTip); + } + [WinFormsTheory] [CommonMemberData(nameof(CommonTestHelper.GetStringNormalizedTheoryData))] public void TabPage_ToolTipText_Set_GetReturnsExpected(string value, string expected)