public async Task Button_Anchor_ResizeOnWindowSizeTallerAsync() { await RunTestAsync(async (form, button) => { button.Anchor = AnchorStyles.Top | AnchorStyles.Bottom; var originalFormSize = form.DisplayRectangle.Size; var originalButtonPosition = button.DisplayRectangle; var mouseDragHandleOnForm = new Point(form.DisplayRectangle.Left + form.DisplayRectangle.Width / 2, form.DisplayRectangle.Bottom); await MoveMouseAsync(form, form.PointToScreen(mouseDragHandleOnForm)); await InputSimulator.SendAsync( form, inputSimulator => inputSimulator.Mouse .LeftButtonDown() .MoveMouseBy(0, form.DisplayRectangle.Height) .LeftButtonUp()); Assert.True(form.DisplayRectangle.Height > originalFormSize.Height); Assert.Equal(originalFormSize.Width, form.DisplayRectangle.Width); Assert.Equal(originalButtonPosition.Location, button.DisplayRectangle.Location); // Still anchored on bottom Assert.Equal(originalFormSize.Height - originalButtonPosition.Bottom, form.DisplayRectangle.Height - button.DisplayRectangle.Bottom); }); }
public async Task Button_Mouse_Press_With_Drag_Off_Button_And_Back_Does_Cause_Button_ClickAsync() { await RunControlPairTestAsync <Button, Button>(async (form, controls) => { (Button control1, Button control2) = controls; int control1ClickCount = 0; int control2ClickCount = 0; control1.Click += (sender, e) => control1ClickCount++; control2.Click += (sender, e) => control2ClickCount++; await MoveMouseToControlAsync(control1); Rectangle rect = control2.DisplayRectangle; Point centerOfRect = GetCenter(rect); Point centerOnScreen = control2.PointToScreen(centerOfRect); Rectangle rect1 = control1.DisplayRectangle; Point centerOfRect1 = new Point(rect1.Left, rect1.Top) + new Size(rect1.Width / 2, rect1.Height / 2); Point centerOnScreen1 = control1.PointToScreen(centerOfRect1); int horizontalResolution = User32.GetSystemMetrics(User32.SystemMetric.SM_CXSCREEN); int verticalResolution = User32.GetSystemMetrics(User32.SystemMetric.SM_CYSCREEN); var virtualPoint = new Point((int)Math.Round(65535.0 / horizontalResolution *centerOnScreen.X), (int)Math.Round(65535.0 / verticalResolution *centerOnScreen.Y)); int horizontalResolution1 = User32.GetSystemMetrics(User32.SystemMetric.SM_CXSCREEN); int verticalResolution1 = User32.GetSystemMetrics(User32.SystemMetric.SM_CYSCREEN); var virtualPoint1 = new Point((int)Math.Round(65535.0 / horizontalResolution1 *centerOnScreen1.X), (int)Math.Round(65535.0 / verticalResolution1 *centerOnScreen1.Y)); await InputSimulator.SendAsync( form, inputSimulator => inputSimulator.Mouse .LeftButtonDown() .MoveMouseTo(virtualPoint.X, virtualPoint.Y) .MoveMouseTo(virtualPoint1.X, virtualPoint1.Y) .LeftButtonUp()); Assert.Equal(1, control1ClickCount); Assert.Equal(0, control2ClickCount); }); }
public async Task Button_DialogResult_ClickDefaultButtonToCloseFormAsync(DialogResult dialogResult) { await RunTestAsync(async (form, button) => { Assert.Equal(DialogResult.None, button.DialogResult); button.DialogResult = dialogResult; await MoveMouseToControlAsync(button); Assert.Equal(CloseReason.None, form.CloseReason); Assert.Equal(DialogResult.None, form.DialogResult); Assert.True(form.Visible); await InputSimulator.SendAsync( form, inputSimulator => inputSimulator.Mouse.LeftButtonClick()); Assert.Equal(CloseReason.None, form.CloseReason); Assert.Equal(dialogResult, form.DialogResult); // The window will only still be visible for DialogResult.None Assert.Equal(dialogResult == DialogResult.None, form.Visible); }); }
public async Task DragDrop_QueryDefaultCursors_Async() { await RunFormWithoutControlAsync(() => new DragDropForm(TestOutputHelper), async (form) => { await MoveMouseToControlAsync(form.ListDragSource); await InputSimulator.SendAsync( form, inputSimulator => inputSimulator.Mouse.LeftButtonDown()); var targetMousePosition = ToVirtualPoint(form.ListDragTarget.PointToScreen(new Point(20, 20))); await InputSimulator.SendAsync( form, inputSimulator => inputSimulator.Mouse .LeftButtonDown() .Sleep(100) .MoveMouseTo(targetMousePosition.X - 40, targetMousePosition.Y) .Sleep(DragDropDelayMS) .MoveMouseTo(targetMousePosition.X, targetMousePosition.Y) .Sleep(DragDropDelayMS) // slight delay so drag&drop triggered .MoveMouseTo(targetMousePosition.X + 2, targetMousePosition.Y + 2) .Sleep(DragDropDelayMS) // slight delay so drag&drop triggered .MoveMouseTo(targetMousePosition.X + 4, targetMousePosition.Y + 4) .Sleep(DragDropDelayMS) .LeftButtonUp() .Sleep(DragDropDelayMS)); Assert.Equal(1, form.ListDragTarget.Items.Count); }); }
public async Task ListView_Click_On_Second_Column_Does_Not_Alter_CheckBoxesAsync() { await RunTestAsync(async (form, listView) => { InitializeItems(listView, View.Details, virtualModeEnabled: false, checkBoxesEnabled: true); foreach (ListViewItem item in listView.Items) { Assert.Equal(0, item.StateImageIndex); Assert.False(item.Selected); } Point listViewCenter = GetCenter(listView.RectangleToScreen(listView.Items[0].SubItems[1].Bounds)); await MoveMouseAsync(form, listViewCenter); await InputSimulator.SendAsync( form, inputSimulator => inputSimulator.Keyboard.KeyDown(VirtualKeyCode.SHIFT) .Mouse.LeftButtonClick()); listViewCenter = GetCenter(listView.RectangleToScreen(listView.Items[2].SubItems[1].Bounds)); await MoveMouseAsync(form, listViewCenter); await InputSimulator.SendAsync( form, inputSimulator => inputSimulator.Mouse.LeftButtonClick() .Keyboard.KeyUp(VirtualKeyCode.SHIFT)); foreach (ListViewItem item in listView.Items) { Assert.Equal(0, item.StateImageIndex); Assert.True(item.Selected); } }); }
public async Task Form_SnapsRightAsync(FormWindowState windowState) { if (!OsVersion.IsWindows11_OrGreater) { return; } await RunEmptyFormTestAsync(async form => { form.Location = new Point(20, 21); form.Size = new Size(300, 310); form.WindowState = windowState; await InputSimulator.SendAsync( form, inputSimulator => inputSimulator.Keyboard.ModifiedKeyStroke(VirtualKeyCode.LWIN, VirtualKeyCode.VK_Z)); // inputSimulator.Sleep appears wildly inconsistent with snap panel timing. Task.Delay does not await Task.Delay(SnapLayoutDelayMS); // Snap right await InputSimulator.SendAsync( form, inputSimulator => inputSimulator.Keyboard.KeyPress(VirtualKeyCode.RIGHT) .KeyPress(VirtualKeyCode.RIGHT) .KeyPress(VirtualKeyCode.RETURN)); await Task.Delay(SnapLayoutDelayMS); // At this point, Windows displays a panel containing all running applications so the // user can select one to dock next to our form. It also takes the keyboard focus away. // If left in this state, subsequently run tests will fail since keyboard focus is not // given to any newly launched window until this panel is dismissed. await InputSimulator.SendAsync( form, inputSimulator => inputSimulator.Keyboard.KeyPress(VirtualKeyCode.ESCAPE)); await Task.Delay(SnapLayoutDelayMS); var screenWorkingArea = Screen.FromControl(form).WorkingArea; int screenMiddleX = screenWorkingArea.X + (screenWorkingArea.Width / 2); int borderSize = (form.Width - form.ClientRectangle.Width) / 2; Assert.True(form.Left <= screenMiddleX); Assert.True(form.Left >= screenMiddleX - borderSize); Assert.True(form.Top <= screenWorkingArea.Y); Assert.True(form.Top >= screenWorkingArea.Y - borderSize); Assert.True(form.Height >= screenWorkingArea.Height); Assert.True(form.Height <= screenWorkingArea.Height + (borderSize * 2)); Assert.True(form.Width >= screenWorkingArea.Width / 2); Assert.True(form.Width <= (screenWorkingArea.Width / 2) + (borderSize * 2)); }); }
public async Task Button_CancelButton_EscapeClicksCancelButtonAsync() { await RunTestAsync(async (form, button) => { form.CancelButton = button; await InputSimulator.SendAsync( form, inputSimulator => inputSimulator.Keyboard.KeyPress(VirtualKeyCode.ESCAPE)); Assert.Equal(DialogResult.Cancel, form.DialogResult); Assert.False(form.Visible); }); }
public async Task ListView_CheckBox_DoubleClick_WorksExpectedAsync(bool virtualModeEnabled, bool checkBoxesEnabled, bool expected) { await RunTestAsync(async (form, listView) => { InitializeItems(listView, View.Details, virtualModeEnabled, checkBoxesEnabled); Point itemCenter = GetCenter(listView.RectangleToScreen(listView.Items[0].Bounds)); await MoveMouseAsync(form, itemCenter); await InputSimulator.SendAsync( form, inputSimulator => inputSimulator.Mouse.LeftButtonDoubleClick()); Assert.Equal(listView.Items[0].Checked, expected); }); }
public async Task PrintPreviewDialog_Hotkey_Ctrl_5Async() { await RunTestAsync(async printPreviewDialog => { await InputSimulator.SendAsync( printPreviewDialog, inputSimulator => inputSimulator.Keyboard.ModifiedKeyStroke(VirtualKeyCode.CONTROL, VirtualKeyCode.VK_5)); // Allow a little time to process the keystroke. await Task.Delay(DelayMS); Assert.Equal(2, printPreviewDialog.PrintPreviewControl.Rows); Assert.Equal(3, printPreviewDialog.PrintPreviewControl.Columns); }); }
public async Task Button_DialogResult_EscapeDoesNotClickFocusedButtonAsync() { await RunTestAsync(async (form, button) => { button.DialogResult = DialogResult.OK; Assert.True(button.Focus()); await InputSimulator.SendAsync( form, inputSimulator => inputSimulator.Keyboard.KeyPress(VirtualKeyCode.ESCAPE)); Assert.Equal(DialogResult.None, form.DialogResult); Assert.True(form.Visible); }); }
public async Task Button_DialogResult_SpaceToClickFocusedButtonAsync() { await RunTestAsync(async (form, button) => { button.DialogResult = DialogResult.OK; Assert.True(button.Focus()); await InputSimulator.SendAsync( form, inputSimulator => inputSimulator.Keyboard.KeyPress(VirtualKeyCode.SPACE)); Assert.Equal(DialogResult.OK, form.DialogResult); Assert.False(form.Visible); }); }
public async Task Button_Hotkey_DoesNotFire_OnClickAsync() { await RunTestAsync(async (form, button) => { bool wasClicked = false; button.Text = "&Click"; button.Click += (x, y) => wasClicked = true; // Send a random ALT+L (the same as SendKeys.SendWait("%l")) await InputSimulator.SendAsync( form, inputSimulator => inputSimulator.Keyboard.ModifiedKeyStroke(VirtualKeyCode.LMENU, VirtualKeyCode.VK_L)); Assert.False(wasClicked); }); }
public async Task Button_Hotkey_Fires_OnClickAsync() { await RunTestAsync(async (form, button) => { Assert.True(InputLanguage.CurrentInputLanguage.LayoutName == "US", "Please, switch to the US input language"); bool wasClicked = false; button.Text = "&Click"; button.Click += (x, y) => wasClicked = true; // Send the shortcut ALT+C (the same as SendKeys.SendWait("%C")) await InputSimulator.SendAsync( form, inputSimulator => inputSimulator.Keyboard.ModifiedKeyStroke(VirtualKeyCode.LMENU, VirtualKeyCode.VK_C)); Assert.True(wasClicked); }); }
public async Task Button_Press_Enter_Fires_OnClickAsync() { await RunTestAsync(async (form, button) => { bool wasClicked = false; button.Text = "&Click"; button.Click += (x, y) => wasClicked = true; await MoveMouseToControlAsync(button); // Send the Enter press await InputSimulator.SendAsync( form, inputSimulator => inputSimulator.Keyboard.KeyPress(VirtualKeyCode.RETURN)); Assert.True(wasClicked); }); }
public async Task Button_AchorNone_NoResizeOnWindowSizeWiderAsync() { await RunTestAsync(async (form, button) => { var originalFormSize = form.DisplayRectangle.Size; var originalButtonPosition = button.DisplayRectangle; var mouseDragHandleOnForm = new Point(form.DisplayRectangle.Right, form.DisplayRectangle.Top + form.DisplayRectangle.Height / 2); await MoveMouseAsync(form, form.PointToScreen(mouseDragHandleOnForm)); await InputSimulator.SendAsync( form, inputSimulator => inputSimulator.Mouse .LeftButtonDown() .MoveMouseBy(form.DisplayRectangle.Width, 0) .LeftButtonUp()); Assert.True(form.DisplayRectangle.Width > originalFormSize.Width); Assert.Equal(originalFormSize.Height, form.DisplayRectangle.Height); Assert.Equal(originalButtonPosition, button.DisplayRectangle); }); }
public async Task DataGridView_ToolTip_DoesNot_ThrowExceptionAsync() { await RunTestAsync(async (form, dataGridView) => { using DataTable dataTable = new(); dataTable.Columns.Add(columnName: "name"); dataTable.Rows.Add(values: "name1"); dataGridView.ShowCellToolTips = true; dataGridView.DataSource = dataTable; Point point = dataGridView.GetCellDisplayRectangle(columnIndex: 0, rowIndex: 0, cutOverflow: false).Location; // Move mouse cursor over any cell of the first row to trigger a tooltip. await InputSimulator.SendAsync( form, inputSimulator => inputSimulator.Mouse.MoveMouseTo(point.X, point.Y)); // Close the form to verify no exceptions thrown while showing the tooltip. // Regression test for https://github.com/dotnet/winforms/issues/5496 form.Close(); dataTable.AcceptChanges(); }); }
public async Task Button_Mouse_Press_Without_Moving_Causes_Button_ClickAsync() { await RunControlPairTestAsync <Button, Button>(async (form, controls) => { (Button control1, Button control2) = controls; int control1ClickCount = 0; int control2ClickCount = 0; control1.Click += (sender, e) => control1ClickCount++; control2.Click += (sender, e) => control2ClickCount++; await MoveMouseToControlAsync(control1); await InputSimulator.SendAsync(form, inputSimulator => inputSimulator.Mouse.LeftButtonDown().LeftButtonUp()); Assert.Equal(1, control1ClickCount); Assert.Equal(0, control2ClickCount); await MoveMouseToControlAsync(control2); await InputSimulator.SendAsync(form, inputSimulator => inputSimulator.Mouse.LeftButtonDown().LeftButtonUp()); Assert.Equal(1, control1ClickCount); Assert.Equal(1, control2ClickCount); }); }
public async Task DesignBehaviorsTests_can_DragDrop_ToolboxItem() { // Regression test for https://github.com/dotnet/winforms/issues/6919, and it verifies that we can successfully // drag and drop a toolbox item from a toolbox on to a designer surface. Application.ThreadException += (s, e) => { // This will preserve the full stack, which otherwise gets replaced throw new Exception(e.Exception.Message, e.Exception); }; await RunSingleControlTestAsync <TreeView>(async (form, treeView) => { // This will indicate when the designer surface has loaded SemaphoreSlim loadSignal = new(0); // This will indicate when the drag and drop operation has completed SemaphoreSlim dndSignal = new(0); form.Size = new(600, 550); treeView.Dock = DockStyle.Left; treeView.Width = 100; // Create a toolbox item and assign it to the node // When we drag the node to the design surface, this will go through the toolbox service API ToolboxItem toolboxItem = new() { TypeName = typeof(SampleControl).FullName, DisplayName = typeof(SampleControl).Name, AssemblyName = typeof(SampleControl).Assembly.GetName() }; TreeNode?node = treeView.Nodes.Add("root"); node.Tag = toolboxItem; // Create the designer surface and all required plumbing SampleDesignerLoader designerLoader = new(); ServiceContainer serviceContainer = new(); DesignSurface designSurface = new(serviceContainer); var designerHost = (IDesignerHost)designSurface.GetService(typeof(IDesignerHost)); serviceContainer.RemoveService(typeof(IToolboxService), false); serviceContainer.AddService(typeof(IToolboxService), new SampleToolboxService(designerHost)); if (designerHost.GetService(typeof(IComponentChangeService)) is IComponentChangeService componentChangeService) { componentChangeService.ComponentAdded += (s, e) => { if (e.Component is Form form) { form.Text = @"RootForm"; form.Size = new Size(400, 400); } else { ((Control)e.Component !).Size = new Size(50, 50); } }; } designSurface.Loaded += (s, e) => { Control rootView = (Control)designSurface.View; rootView.Dock = DockStyle.Fill; form.Controls.Add(rootView); rootView.BringToFront(); // Indicate that we have finished loading the designer surface loadSignal.Release(); }; treeView.ItemDrag += treeView_ItemDrag; designSurface.BeginLoad(designerLoader); // Wait for the designer surface to load await loadSignal.WaitAsync(millisecondsTimeout: 3_000); // Initiate the drag and drop and wait for the signal that it finished var dndStartCoordinates = treeView.PointToScreen(node.Bounds.Location); await InitiateDrangDropAsync(form, dndStartCoordinates, (Control)designSurface.View); await dndSignal.WaitAsync(millisecondsTimeout: 3_000); return; void treeView_ItemDrag(object?sender, ItemDragEventArgs e) { if (designerHost?.GetService(typeof(IToolboxService)) is not IToolboxService toolboxService || e.Item is not TreeNode node || node.Tag is not ToolboxItem toolboxItem) { return; } var dataObject = toolboxService.SerializeToolboxItem(toolboxItem) as DataObject; var effects = node.TreeView.DoDragDrop(dataObject !, DragDropEffects.Copy); } async Task InitiateDrangDropAsync(Form form, Point startCoordinates, Control rootView) { var virtualPointStart = ToVirtualPoint(startCoordinates); startCoordinates.Offset(110, 50); var virtualPointEnd = ToVirtualPoint(startCoordinates); await InputSimulator.SendAsync( form, inputSimulator => inputSimulator.Mouse.MoveMouseTo(virtualPointStart.X + 6, virtualPointStart.Y + 6) .LeftButtonDown() .Sleep(100) .MoveMouseTo(virtualPointEnd.X, virtualPointEnd.Y) // The d'n'd is very finicky, and if we just call LeftButtonUp() // it won't work... It'd for some reason think we'd left the control instead. // // To work around it - give it a full second to react and then // simulate a mouse click. .Sleep(100) .LeftButtonClick()); dndSignal.Release(); } }); }
public async Task ListView_Group_NavigateKeyboard_SucceedsAsync() { await RunTestAsync(async (form, listView) => { var group = new ListViewGroup($"Group 1", HorizontalAlignment.Left) { CollapsedState = ListViewGroupCollapsedState.Expanded }; var item1 = new ListViewItem("g1-1") { Group = group }; var item2 = new ListViewItem("g1-2") { Group = group }; var item3 = new ListViewItem("g1-3") { Group = group }; listView.Groups.Add(group); listView.Items.AddRange(new[] { item1, item2, item3 }); listView.Focus(); bool collapsedStateChangedFired = false; listView.GroupCollapsedStateChanged += (sender, e) => collapsedStateChangedFired = true; item1.Selected = true; await InputSimulator.SendAsync(form, inputSimulator => inputSimulator.Keyboard.KeyPress(VirtualKeyCode.RIGHT)); Assert.False(item1.Selected); Assert.True(item2.Selected); Assert.False(item3.Selected); Assert.False(collapsedStateChangedFired); await InputSimulator.SendAsync(form, inputSimulator => inputSimulator.Keyboard.KeyPress(VirtualKeyCode.RIGHT)); Assert.False(item1.Selected); Assert.False(item2.Selected); Assert.True(item3.Selected); Assert.False(collapsedStateChangedFired); await InputSimulator.SendAsync(form, inputSimulator => inputSimulator.Keyboard.KeyPress(VirtualKeyCode.RIGHT)); Assert.False(item1.Selected); Assert.False(item2.Selected); Assert.True(item3.Selected); Assert.False(collapsedStateChangedFired); await InputSimulator.SendAsync(form, inputSimulator => inputSimulator.Keyboard.KeyPress(VirtualKeyCode.LEFT).KeyPress(VirtualKeyCode.LEFT)); Assert.True(item1.Selected); Assert.False(item2.Selected); Assert.False(item3.Selected); Assert.False(collapsedStateChangedFired); await InputSimulator.SendAsync(form, inputSimulator => inputSimulator.Keyboard.KeyPress(VirtualKeyCode.LEFT)); Assert.True(item1.Selected); Assert.False(item2.Selected); Assert.False(item3.Selected); Assert.False(collapsedStateChangedFired); // Selects header, which selects all items in group await InputSimulator.SendAsync(form, inputSimulator => inputSimulator.Keyboard.KeyPress(VirtualKeyCode.UP)); Assert.True(item2.Selected); Assert.True(item2.Selected); Assert.True(item2.Selected); Assert.False(collapsedStateChangedFired); // Collapse group await InputSimulator.SendAsync(form, inputSimulator => inputSimulator.Keyboard.KeyPress(VirtualKeyCode.LEFT).KeyPress(VirtualKeyCode.UP).KeyPress(VirtualKeyCode.LEFT)); Assert.Equal(ListViewGroupCollapsedState.Collapsed, group.CollapsedState); Assert.True(collapsedStateChangedFired); // Expand group collapsedStateChangedFired = false; await InputSimulator.SendAsync(form, inputSimulator => inputSimulator.Keyboard.KeyPress(VirtualKeyCode.UP).KeyPress(VirtualKeyCode.RIGHT)); Assert.True(collapsedStateChangedFired); Assert.Equal(ListViewGroupCollapsedState.Expanded, group.CollapsedState); }); }
public async Task RichTextBox_Click_On_Friendly_Name_Link_Provides_Hidden_Link_SpanAsync() { await RunTestAsync(async (form, richTextBox) => { richTextBox.Rtf = @"{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang4105{\fonttbl{\f0\fnil\fcharset0 Calibri;}} {\*\generator Riched20 10.0.17134}\viewkind4\uc1 {\field{\*\fldinst { HYPERLINK ""http://www.google.com"" }}{\fldrslt {Click link #1}}} \pard\sa200\sl276\slmult1\f0\fs22\lang9 for more information.\par {\field{\*\fldinst { HYPERLINK ""http://www.google.com"" }}{\fldrslt {Click link #2}}} \pard\sa200\sl276\slmult1\f0\fs22\lang9 for more information.\par {\field{\*\fldinst { HYPERLINK ""http://www.google.com"" }}{\fldrslt {Click link #3}}} \pard\sa200\sl276\slmult1\f0\fs22\lang9 for more information.\par }"; Point previousPosition = new(); BOOL setOldCursorPos = GetPhysicalCursorPos(ref previousPosition); LinkClickedEventArgs?result = null; LinkClickedEventHandler handler = (sender, e) => result = e; richTextBox.LinkClicked += handler; try { Point pt = richTextBox.PointToScreen(richTextBox.GetPositionFromCharIndex(richTextBox.Text.IndexOf("Click link #2"))); // Adjust point a bit to make sure we are clicking inside the character cell instead of on its edge. pt.X += 2; pt.Y += 2; await MoveMouseAsync(form, pt); await InputSimulator.SendAsync( form, inputSimulator => inputSimulator.Mouse.LeftButtonClick()); if (setOldCursorPos.IsTrue()) { await MoveMouseAsync(form, previousPosition); } // Let the event queue drain after clicking, before moving the cursor back to the old position. Application.DoEvents(); } finally { richTextBox.LinkClicked -= handler; if (setOldCursorPos.IsTrue()) { // Move cursor to the old position. await InputSimulator.SendAsync( form, inputSimulator => inputSimulator.Mouse.MoveMouseTo(previousPosition.X, previousPosition.Y)); Application.DoEvents(); } } Assert.NotNull(result); Assert.True(result !.LinkStart + result.LinkLength <= richTextBox.Text.Length); Assert.Equal(result.LinkText, richTextBox.Text.Substring(result.LinkStart, result.LinkLength)); // This assumes the input span is the hidden text of a "friendly name" URL, // which is what the native control will pass to the LinkClicked event instead // of the actual span of the clicked display text. var displayText = GetTextFromRange(richTextBox, result.LinkStart, result.LinkLength, range => { // Move the cursor to the end of the hidden area we are currently located in. range.EndOf(TomHidden, 0); // Extend the cursor to the end of the display text of the link. range.EndOf(TomLink, 1); }); Assert.Equal("Click link #2", displayText); }); }
public async Task RichTextBox_Click_On_Custom_Link_Preceeded_By_Hidden_Text_Provides_Displayed_Link_SpanAsync() { await RunTestAsync(async (form, richTextBox) => { richTextBox.Rtf = @"{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang4105{\fonttbl{\f0\fnil\fcharset0 Calibri;}} {\*\generator Riched20 10.0.17134}\viewkind4\uc1\pard\sa200\sl276\slmult1\f0\fs22\lang9 This is hidden text preceeding a \v #link1#\v0 custom link.\par This is hidden text preceeding a \v #link2#\v0 custom link.\par This is hidden text preceeding a \v #link3#\v0 custom link.\par }"; MakeLink(richTextBox, "#link1#custom link"); MakeLink(richTextBox, "#link2#custom link"); MakeLink(richTextBox, "#link3#custom link"); Point previousPosition = new(); BOOL setOldCursorPos = GetPhysicalCursorPos(ref previousPosition); LinkClickedEventArgs?result = null; LinkClickedEventHandler handler = (sender, e) => result = e; richTextBox.LinkClicked += handler; try { Point pt = richTextBox.PointToScreen(richTextBox.GetPositionFromCharIndex(richTextBox.Text.IndexOf("#link2#custom link"))); // Adjust point a bit to make sure we are clicking inside the character cell instead of on its edge. pt.X += 2; pt.Y += 2; await MoveMouseAsync(form, pt); await InputSimulator.SendAsync( form, inputSimulator => inputSimulator.Mouse.LeftButtonClick()); if (setOldCursorPos.IsTrue()) { await MoveMouseAsync(form, previousPosition); } // Let the event queue drain after clicking, before moving the cursor back to the old position. Application.DoEvents(); } finally { richTextBox.LinkClicked -= handler; if (setOldCursorPos.IsTrue()) { // Move cursor to the old position. await InputSimulator.SendAsync( form, inputSimulator => inputSimulator.Mouse.MoveMouseTo(previousPosition.X, previousPosition.Y)); Application.DoEvents(); } } Assert.NotNull(result); Assert.True(result !.LinkStart + result.LinkLength <= richTextBox.Text.Length); Assert.Equal(result.LinkText, richTextBox.Text.Substring(result.LinkStart, result.LinkLength)); // This assumes the input span is a custom link preceeded by hidden text. var hiddenText = GetTextFromRange(richTextBox, result.LinkStart, result.LinkLength, range => { // Move the cursor to the start of the link we are currently located in. range.StartOf(TomLink, 0); // Extend the cursor to the start of the hidden area preceeding the link. range.StartOf(TomHidden, 1); }); Assert.Equal("#link2#", hiddenText); }); }