WPF: Simulate user input using TestApi

Source: Internet
Author: User

References:

(1). WPF: automatically click a FrameworkElement

(2). TestApi-a library of Test APIs

(3). Introduction to TestApi-Part 1: Input Injection APIs

 

1. Five Ways to simulate user input:

(A) Directly call the UI element method, for example: Button. IsPressed

(B) Use available interfaces (UIA, MSAA, etc.), such as: AutomationElement

(C) Use the underlying Input simulation, which is related to the operating system, such as SendInput Win32 API and Raw Input Win32 API in Windows.

(D) Use device-driven Simulation

(E) Use a robot to simulate human operations, such as hitting a keyboard

Method A is framework-level, valid only for WPF, and invalid for Winform;

Method B is lower than the framework level, but there are still many restrictions, because some frameworks require different implementations of available interfaces;

Methods C and D are at the operating system level, where D is more difficult to implement than C;

Method E is a commonly used method (I think it is only in the United States, Khan), although it is expensive and slow.

TestApiThe most common methods of B and C are provided.AutomationUtilitiesClass implementation.MouseAndKeyboardTwo class implementations.

 

2. Example of simulating using TestApi

Example 1:WPF WindowAnd click the nextWPF Button, UseAutomationUtilitiesAndMouseClass.

 //
// EXAMPLE #1
// This code below discovers and clicks the Close button in an About
//dialog box, thus dismissing the About dialog box.
//

string aboutDialogName = "About";
string closeButtonName = "Close";

AutomationElementCollection aboutDialogs = AutomationUtilities.FindElementsByName(
AutomationElement.RootElement,
aboutDialogName);

AutomationElementCollection closeButtons = AutomationUtilities.FindElementsByName(
aboutDialogs[0],
closeButtonName);

//
// You can either invoke the discovered control, through its invoke
// pattern...
//

InvokePattern p =
closeButtons[0].GetCurrentPattern(InvokePattern.Pattern) as InvokePattern;
p.Invoke();

//
// ... or you can handle the Mouse directly and click on the control.
//

Mouse.MoveTo(closeButton.GetClickablePoint());
Mouse.Click(MouseButton.Left);

Example 2: automatically search forTextBoxAnd type in it, useMouseAndKeyboardClass

 //
// EXAMPLE #2
// Discover the location of a TextBox with a given name.
//

string textboxName = "ssnInputField";

AutomationElement textBox = AutomationUtilities.FindElementsByName(
AutomationElement.RootElement,
textboxName)[0];

Point textboxLocation = textbox.GetClickablePoint();

//
// Move the mouse to the textbox, click, then type something
//

Mouse.MoveTo(textboxLocation);
Mouse.Click(MouseButton.Left);

Keyboard.Type("Hello world.");
Keyboard.Press(Key.Shift);
Keyboard.Type("hello, capitalized world.");
Keyboard.Release(Key.Shift);

 

3. Postscript

TestApiInMouse AndKeyboardClass can be used in any form application. It has nothing to do with the test framework and test process, and provides source code and documentation. You can integrate the class into your project, or directly reference the Dll.

It should be noted that although TestApi provides such a simple method to implement UI testing, UI testing is a tricky and complex task and should be avoided whenever possible. In general, it is better to adopt multi-tier design mode in the application, and design a lightweight/thin (thin) UI to avoid UI testing as much as possible.

 

4. Appendix: how to calculate the widget location

To independently calculate the widget element location, instead of using the GetClickablePoint () method in TestApi, you can use the following method:

1: /// <summary>

2: // Get mouse move to location

3: /// </summary>

4: // <param name = "element"> element </param>

5: // <param name = "logicalOffset"> wpf logical pixel offset </param>

6: // <returns> screen physical pixel location </returns>

7: public static System. Drawing. Point GetMoveToLocation (FrameworkElement element, Point logicalOffset)

8 :{

9: Point mouseLocation = default (Point );

10: FlowDirection flowDirection = Window. GetWindow (element). FlowDirection;

11:

12: // We don't need to convert element location to physical screen pixel because wpf takes care of it.

13: Point elementLocation = element. PointToScreen (new Point ());

14:

15: // We need to convert offset to physical screen pixel since we're pass in wpf logical pixel

16: double physicalXOffset = ConvertToPhysicalPixel (logicalOffset. X );

17: double physicalYOffset = ConvertToPhysicalPixel (logicalOffset. Y );

18:

19: switch (flowDirection)

20 :{

21: case FlowDirection. LeftToRight:

22: mouseLocation = new Point (elementLocation. X + physicalXOffset, elementLocation. Y + physicalYOffset );

23: break;

24: case FlowDirection. RightToLeft:

25: // We need to subtract physical offsetX because the element location starting point is in right most

26: mouseLocation = new Point (elementLocation. X-physicalXOffset, elementLocation. Y + physicalYOffset );

27: break;

28 :}

29:

30: return new System. Drawing. Point (Convert. ToInt32 (mouseLocation. X), Convert. ToInt32 (mouseLocation. Y ));

31 :}

32:

33: // <summary>

34: // WPF has its own pixel system in double value type, and screen pixel between des different DPIs in int value type.

35: // In 96 dpi, wpf and screen pixels are the same, but other dpi, we need to convert wpf logical pixel to screen physical

36: // pixel by using formula (wpf pixel value * dpi/96.0 ).

37: // </summary>

38: // <param name = "logicalPixel"> Logical (WPF) pixel value </param>

39: // <returns> Physical (Screen) pixel value </returns>

40: public static int ConvertToPhysicalPixel (double logicalPixel)

41 :{

42: return Convert. ToInt32 (logicalPixel * GetDpi ()/96.0 );

43 :}

44:

45: // <summary>

46: // Get DPI of the system

47: // </summary>

48: // <returns> </returns>

49: public static float GetDpi ()

50 :{

51: using (System. Drawing. Graphics graph = System. Drawing. Graphics. FromHwnd (IntPtr. Zero ))

52 :{

53: if (graph = null)

54 :{

55: throw new NullReferenceException ("Graphics not found ");

56 :}

57:

58: if (! Graph. DpiX. Equals (graph. DpiY ))

59 :{

60: throw new ArithmeticException ("DpiX! = DpiY ");

61 :}

62:

63: return graph. DpiX;

64 :}

65 :}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.