UIAutomation 自动化

article/2025/10/15 4:57:50

Introduction

UI Automation是Microsoft .NET 3.0框架下提供的一种用于自动化测试的技术,是在MSAA基础上建立的,MSAA就是Microsoft Active Accessibility。UI Automation在某些方面超过了MSAA,UI自动化提供了Windows Vista中,微软Windows XP的全部功能,和Windows Server 2003。

在UI Automation中,所有的窗体、控件都表现为一个AutomationElement, AutomationElement 中包含此控件或窗体的属性,在实现自动化的过程中,我们通过其相关属性进行对控件自动化操作。对于UI用户界面来说,所有显示在桌面上的UI,其实际是一个UI Tree,根节点是desktop。我们可以使用UI Spy或者是SPY++来获得Window和Control的相关信息。在UI Automation里,根节点表示为AutomationElemnet.RootElement. 通过根节点,我们可以通过窗体或控件的Process Id、Process Name或者Window Name找到相应的子AutomationElement,例如Dialog、Button、TextBox、Checkbox等标准控件,通过控件所对应的Pattern进行相关的操作。

UI Automation structure

如下图所示:


1. 在服务端由UIAutomationProvider.dll和UIAutomationTypes.dll提供。

     2. 在客户端由UIAutomationClient.dll和UIAutomationTypes.dll提供。

     3. UIAutomationCore.dll为UI自动化的核心部分,负责Server端和Client端的交互。

     4. UIAUtomationClientSideProvides.dll为客户端程序提供自动化支持。

使用UI Automation实现自动化测试--2

本文通过一个实例来介绍怎样使用UI Automation实现软件的自动化测试。

1. 首先建立一个待测试的winform程序,即UI Automation的服务端。

下面是button事件处理程序。

private void button1_Click(object sender, EventArgs e)

{

     int i = int.Parse(textBox1.Text);

     int j = int.Parse(textBox2.Text);

     textBox3.Text = (i + j).ToString();

}

2. 建立一个测试程序,做UI Automaion的客户端。

添加引用:UIAutomationClient.dll 和 UIAutomationTypes.dll


  2
using System.Diagnostics;

  3
using System.Threading;

  4
using System.Windows.Automation.Provider;

  5
using System.Windows.Automation.Text;

  6
using System.Windows.Automation;

  7

  8
namespace UIAutomationTest

  9
{

 10
    class Program

 11
    {

 12
        static void Main(string[] args)

 13
        {

 14
            try

 15
            {

 16
                Console.WriteLine("\nBegin WinForm UIAutomation test run\n");

 17
                // launch Form1 application

 18
                // get refernce to main Form control

 19
                // get references to user controls

 20
                // manipulate application

 21
                // check resulting state and determine pass/fail

 22

 23
                Console.WriteLine("\nBegin WinForm UIAutomation test run\n");

 24
                Console.WriteLine("Launching WinFormTest application");

 25
                //启动被测试的程序

 26
                Process p = Process.Start(@"E:\Project\WinFormTest\WinFormTest\bin\Debug\WinFormTest.exe");

 27

 28
                //自动化根元素

 29
                AutomationElement aeDeskTop = AutomationElement.RootElement;

 30

 31
                Thread.Sleep(2000);

 32
                AutomationElement aeForm = AutomationElement.FromHandle(p.MainWindowHandle);

 33
                //获得对主窗体对象的引用,该对象实际上就是 Form1 应用程序(方法一)

 34
                //if (null == aeForm)

 35
                //{

 36
                //    Console.WriteLine("Can not find the WinFormTest from.");

 37
                //}

 38

 39
                //获得对主窗体对象的引用,该对象实际上就是 Form1 应用程序(方法二)

 40
                int numWaits = 0;

 41
                do

 42
                {

 43
                    Console.WriteLine("Looking for WinFormTest……");

 44
                    //查找第一个自动化元素

 45
                    aeForm = aeDeskTop.FindFirst(TreeScope.Children, new PropertyCondition(

 46
                        AutomationElement.NameProperty, "Form1"));

 47
                    ++numWaits;

 48
                    Thread.Sleep(100);

 49
                } while (null == aeForm && numWaits < 50);

 50
                if (null == aeForm)

 51
                    throw new NullReferenceException("Failed to find WinFormTest.");

 52
                else

 53
                    Console.WriteLine("Found it!");

 54

 55
                Console.WriteLine("Finding all user controls");

 56
                //找到第一次出现的Button控件

 57
                AutomationElement aeButton = aeForm.FindFirst(TreeScope.Children,

 58
                  new PropertyCondition(AutomationElement.NameProperty, "button1"));

 59

 60
                //找到所有的TextBox控件

 61
                AutomationElementCollection aeAllTextBoxes = aeForm.FindAll(TreeScope.Children,

 62
                    new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit));

 63

 64
                // 控件初始化的顺序是先初始化后添加到控件

 65
                // this.Controls.Add(this.textBox3);                  

 66
                // this.Controls.Add(this.textBox2);

 67
                // this.Controls.Add(this.textBox1);

 68

 69
                AutomationElement aeTextBox1 = aeAllTextBoxes[2];

 70
                AutomationElement aeTextBox2 = aeAllTextBoxes[1];

 71
                AutomationElement aeTextBox3 = aeAllTextBoxes[0];

 72

 73
                Console.WriteLine("Settiing input to '30'");

 74
                //通过ValuePattern设置TextBox1的值

 75
                ValuePattern vpTextBox1 = (ValuePattern)aeTextBox1.GetCurrentPattern(ValuePattern.Pattern);

 76
                vpTextBox1.SetValue("30");

 77
                Console.WriteLine("Settiing input to '50'");

 78
                //通过ValuePattern设置TextBox2的值

 79
                ValuePattern vpTextBox2 = (ValuePattern)aeTextBox2.GetCurrentPattern(ValuePattern.Pattern);

 80
                vpTextBox2.SetValue("50");

 81
                Thread.Sleep(1500);

 82
                Console.WriteLine("Clickinig on button1 Button.");

 83
                //通过InvokePattern模拟点击按钮

 84
                InvokePattern ipClickButton1 = (InvokePattern)aeButton.GetCurrentPattern(InvokePattern.Pattern);

 85
                ipClickButton1.Invoke();

 86
                Thread.Sleep(1500);

 87

 88
                //验证计算的结果与预期的结果是否相符合

 89
                Console.WriteLine("Checking textBox3 for '80'");

 90
                TextPattern tpTextBox3 = (TextPattern)aeTextBox3.GetCurrentPattern(TextPattern.Pattern);

 91
                string result = tpTextBox3.DocumentRange.GetText(-1);//获取textbox3中的值

 92
                //获取textbox3中的值

 93
                //string result = (string)aeTextBox2.GetCurrentPropertyValue(ValuePattern.ValueProperty);

 94
                if ("80" == result)

 95
                {

 96
                    Console.WriteLine("Found it.");

 97
                    Console.WriteLine("TTest scenario: *PASS*");

 98
                }

 99
                else

100
                {

101
                    Console.WriteLine("Did not find it.");

102
                    Console.WriteLine("Test scenario: *FAIL*");

103
                }

104

105
                Console.WriteLine("Close application in 5 seconds.");

106
                Thread.Sleep(5000);

107
                //实现关闭被测试程序

108
                WindowPattern wpCloseForm = (WindowPattern)aeForm.GetCurrentPattern(WindowPattern.Pattern);

109
                wpCloseForm.Close();

110

111
                Console.WriteLine("\nEnd test run\n");

112
            }

113
            catch (Exception ex)

114
            {

115
                Console.WriteLine("Fatal error: " + ex.Message);

116
            }

117
        }

118
    }

119
}

120

使用UI Automation实现自动化测试--3

Chapter 3  UI Automation中的几个重要属性

Control Tree of the AutomationElement

在UI Automation控件树中,根节点为Desktop window, 其他运行在用户桌面的窗体都作为Desktop window的子节点。

如下图所示:

Desktop window可通过AutomationElement.RootElement属性获取,子节点中的窗体或对话框可通过

AutomationElement.RootElement.FindAll(TreeScope.Descendants, condition)


AutomationElement.RootElement.FindFirt(TreeScope.Descendants, condition)来获取.

AutomationElement property

在UI Automation中有如下几个重要属性:

  1. AutomationIdProperty: 通过AutomationId来查找AutomationElement。
  2. NameProperty:通过控件的Name属性来查找AutomationElement。
  3. ControlType:通过控件的类型来查找AutomationElement
  4. AutomationId: 唯一地标识自动化元素,将其与同级相区分。
  5. Name:  WPF 按钮的Content 属性、Win32 按钮的Caption 属性以及 HTML 图像的ALT 属性都映射到 UI 自动化视图中的同一个属性 Name。

注:PropertyCondition类是用来对相关属性进行条件匹配,在控件树中查找控件时,可以通过最佳匹配来找到相应的控件。

如下代码列出了使用不同的属性来构建PropertyCondition,通过PropertyCondition来查找控件树中的控件.


public class PropertyConditions
    {
        static PropertyCondition propertyCondition;
        /// <summary>
        /// Create PropertyCondition by AutomationId
        /// </summary>
        /// <param name="automationId">Control AutomationId</param>
        /// <returns>Return PropertyCondition instance</returns>
        public static PropertyCondition GetAutomationIdProperty(object automationId)
        {
            propertyCondition = new PropertyCondition(AutomationElement.AutomationIdProperty, automationId);
            return propertyCondition;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="controlType"></param>
        /// <returns></returns>
        public static PropertyCondition GetControlTypeProperty(object controlType)
        {
            propertyCondition = new PropertyCondition(AutomationElement.ControlTypeProperty, controlType);
            return propertyCondition;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="controlName"></param>
        /// <returns></returns>
        public static PropertyCondition GetNameProperty(object controlName)
        {
            propertyCondition = new PropertyCondition(AutomationElement.NameProperty, controlName);
            return propertyCondition;
        }
        /// <summary>
        /// Find element by specific PropertyCondition
        /// </summary>
        /// <param name="condition">PropertyCondition instance</param>
        /// <returns>Target automation element</returns>
        public static AutomationElement FindElement(PropertyCondition condition)
        {
            return AutomationElement.RootElement.FindFirst(TreeScope.Descendants, condition);
        }
    }

使用UI Automation实现自动化测试--4.1 (DockPattern)

DockPattern用于操作可停靠容器控件,我们最熟悉的VS2005/2008中的ToolBox,Solution Explorer都可以设置不同的DockPosition, 但是目前并不支持DockPattern,所以无法做为实例来讲。使用DockPattern的前提为控件支持DockPattern。 DockPattern中的DockPosition有六个枚举变量,即Bottom、Left、Right、Top、Fill和None。如果控件支持DockPattern, 则可以获取相对应的DockPosition以及设置控件的DockPosition。

如下代码是获取控件的DockPattern、获取控件当前的DockPosition以及设置控件的DockPosition。


#region DockPattern helper
        /// <summary>
        /// Get DockPattern
        /// </summary>
        /// <param name="element">AutomationElement instance</param>
        /// <returns>DockPattern instance</returns>
        public static DockPattern GetDockPattern(AutomationElement element)
        {
            object currentPattern;
            if (!element.TryGetCurrentPattern(DockPattern.Pattern, out currentPattern))
            {
                throw new Exception(string.Format("Element with AutomationId '{0}' and Name '{1}' does not support the DockPattern.",
                    element.Current.AutomationId, element.Current.Name));
            }
            return currentPattern as DockPattern;
        }
        /// <summary>
        /// Get DockPosition
        /// </summary>
        /// <param name="element">AutomationElement instance</param>
        /// <returns>DockPosition instance</returns>
        public static DockPosition GetDockPosition(AutomationElement element)
        {
            return GetDockPattern(element).Current.DockPosition;
        }
        /// <summary>
        /// Set DockPosition
        /// </summary>
        /// <param name="element">AutomationElement instance</param>
        public static void SetDockPattern(AutomationElement element, DockPosition dockPosition)
        {
            GetDockPattern(element).SetDockPosition(dockPosition);
        }
        #endregion

使用UI Automation实现自动化测试--4.2 (ExpandCollapsePattern)

ExpandCollapsePattern

表示以可视方式进行展开(以显示内容)和折叠(以隐藏内容)的控件。例如ComboBox控件支持ExpandCollapsePattern。

ExpandCollapsePattern有两个主要方法:

Expand()方法:隐藏 AutomationElement 的全部子代节点、控件或内容。

Collapse()方法:显示 AutomationElement 的全部子节点、控件或内容。

      以下代码是用ExpandCollapsePattern来测试ComboBox控件的Expand和Collapse。

using System;
using System.Text;
using System.Diagnostics;
using System.Threading;
using System.Windows.Automation;
namespace UIATest
{
    class Program
    {
        static void Main(string[] args)
        {
            Process process = Process.Start(@"F:\CSharpDotNet\AutomationTest\ATP\WpfApp\bin\Debug\WpfApp.exe");
            int processId = process.Id;
            AutomationElement element = FindElementById(processId, "comboBox1");
            ExpandCollapsePattern currentPattern = GetExpandCollapsePattern(element);
            currentPattern.Expand();
            Thread.Sleep(1000);
            currentPattern.Collapse();
        }
        /// <summary>
        /// Get the automation elemention of current form.
        /// </summary>
        /// <param name="processId">Process Id</param>
        /// <returns>Target element</returns>
        public static AutomationElement FindWindowByProcessId(int processId)
        {
            AutomationElement targetWindow = null;
            int count = 0;
            try
            {
                Process p = Process.GetProcessById(processId);
                targetWindow = AutomationElement.FromHandle(p.MainWindowHandle);
                return targetWindow;
            }
            catch (Exception ex)
            {
                count++;
                StringBuilder sb = new StringBuilder();
                string message = sb.AppendLine(string.Format("Target window is not existing.try #{0}", count)).ToString();
                if (count > 5)
                {
                    throw new InvalidProgramException(message, ex);
                }
                else
                {
                    return FindWindowByProcessId(processId);
                }
            }
        }
        /// <summary>
        /// Get the automation element by automation Id.
        /// </summary>
        /// <param name="windowName">Window name</param>
        /// <param name="automationId">Control automation Id</param>
        /// <returns>Automatin element searched by automation Id</returns>
        public static AutomationElement FindElementById(int processId, string automationId)
        {
            AutomationElement aeForm = FindWindowByProcessId(processId);
            AutomationElement tarFindElement = aeForm.FindFirst(TreeScope.Descendants,
            new PropertyCondition(AutomationElement.AutomationIdProperty, automationId));
            return tarFindElement;
        }
        ExpandCollapsePattern helper
    }
}

      以下代码为被测程序的xaml文件:


 1
<Window x:Class="WpfApp.Window1"

 2
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

 3
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

 4
    Title="Window1" Height="219" Width="353">

 5
    <Grid>

 6
        <ComboBox Name="comboBox1" Height="23" VerticalAlignment="Top" Margin="94,58,0,0" HorizontalAlignment="Left" Width="119">

 7
            <ComboBoxItem>kaden</ComboBoxItem>

 8
            <ComboBoxItem>sam</ComboBoxItem>

 9
        </ComboBox>

10
    </Grid>

11
</Window>

使用UI Automation实现自动化测试--4.3 (InvokePattern)

InvokePattern

InvokePattern是UIA中最常用的Pattern之一,WPF和Winform中的button控件都支持InvokePattern。

对InvokePattern的Invoke()方法的调用应立即返回,没有出现阻止情况。但是,此行为完全依赖于 Microsoft UI 自动化提供程序实现。在调用 Invoke() 会引起阻止问题(如Winform中的模式对话框,但是WPF中的对话框的处理方式和winform不同,所以可以使用Invoke()方法来操作WPF中的模式对话框,因为WPF中的模式对话框不会出现阻止的问题)的情况下,要调用此方法,则需要另起线程来操作。


using System;
using System.Text;
using System.Diagnostics;
using System.Threading;
using System.Windows.Automation;
namespace UIATest
{
    class Program
    {
        static void Main(string[] args)
        {
            Process process = Process.Start(@"F:\CSharpDotNet\AutomationTest\ATP\WpfApp\bin\Debug\WpfApp.exe");
            int processId = process.Id;
            AutomationElement element = FindElementById(processId, "button1");
            InvokePattern currentPattern = GetInvokePattern(element);
            currentPattern.Invoke();
        }
        /// <summary>
        /// Get the automation elemention of current form.
        /// </summary>
        /// <param name="processId">Process Id</param>
        /// <returns>Target element</returns>
        public static AutomationElement FindWindowByProcessId(int processId)
        {
            AutomationElement targetWindow = null;
            int count = 0;
            try
            {
                Process p = Process.GetProcessById(processId);
                targetWindow = AutomationElement.FromHandle(p.MainWindowHandle);
                return targetWindow;
            }
            catch (Exception ex)
            {
                count++;
                StringBuilder sb = new StringBuilder();
                string message = sb.AppendLine(string.Format("Target window is not existing.try #{0}", count)).ToString();
                if (count > 5)
                {
                    throw new InvalidProgramException(message, ex);
                }
                else
                {
                    return FindWindowByProcessId(processId);
                }
            }
        }
        /// <summary>
        /// Get the automation element by automation Id.
        /// </summary>
        /// <param name="windowName">Window name</param>
        /// <param name="automationId">Control automation Id</param>
        /// <returns>Automatin element searched by automation Id</returns>
        public static AutomationElement FindElementById(int processId, string automationId)
        {
            AutomationElement aeForm = FindWindowByProcessId(processId);
            AutomationElement tarFindElement = aeForm.FindFirst(TreeScope.Descendants,
            new PropertyCondition(AutomationElement.AutomationIdProperty, automationId));
            return tarFindElement;
        }
        #region InvokePattern helper
        /// <summary>
        /// Get InvokePattern
        /// </summary>
        /// <param name="element">AutomationElement instance</param>
        /// <returns>InvokePattern instance</returns>
        public static InvokePattern GetInvokePattern(AutomationElement element)
        {
            object currentPattern;
            if (!element.TryGetCurrentPattern(InvokePattern.Pattern, out currentPattern))
            {
                throw new Exception(string.Format("Element with AutomationId '{0}' and Name '{1}' does not support the InvokePattern.",
                    element.Current.AutomationId, element.Current.Name));
            }
            return currentPattern as InvokePattern;
        }
        #endregion
    }
}


被测程序xaml代码如下:


<Window x:Class="WpfApp.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="219" Width="353">
    <Grid>
        <Button Height="23" HorizontalAlignment="Left" Click="button1_Click" Margin="50,0,0,62" Name="button1" VerticalAlignment="Bottom" Width="75">Button</Button>
    </Grid>
</Window>


对应的cs文件:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApp
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
        }
        private void button1_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show("Use InvokePattern invoke button.");
        }
    }
}

      本文主要针对InvokePattern的Invoke方法来操作button控件。

使用UI Automation实现自动化测试--4.4 (ValuePattern)

ValuePattern是UI Automation中最常见的Pattern之一,Winform和WPF的TextBox控件都支持ValuePattern。

ValuePattern的一个重要的方法是SetValue,在允许调用 SetValue 之前,控件应将其 IsEnabledProperty 设置为 true 并将其 IsReadOnlyProperty 设置为 false。

通过ValuePattern的Current属性可以获得控件的value和IsReadOnly属性。

实现 Value 控件模式时,请注意以下准则和约定:

如果任何项的值是可编辑的,则诸如 ListItem 和 TreeItem 等控件必须支持 ValuePattern,而不管控件的当前编辑模式如何。如果子项是可编辑的,则父控件还必须支持ValuePattern。

    下面的例子是通过ValuePattern来给TextBox设置和获取值:


 1using System;
 2using System.Text;
 3using System.Diagnostics;
 4using System.Threading;
 5using System.Windows.Automation;
 6
 7namespace UIATest
 8{
 9    class Program
10    {
11        static void Main(string[] args)
12        {
13            Process process = Process.Start(@"F:\CSharpDotNet\AutomationTest\ATP\WpfApp\bin\Debug\WpfApp.exe");
14            int processId = process.Id;
15            AutomationElement element = FindElementById(processId, "textBox1");
16            ValuePattern currentPattern = GetValuePattern(element);
17            Console.WriteLine("Is read only:'{0}', TextBox text is:'{1}'", currentPattern.Current.IsReadOnly, currentPattern.Current.Value);
18            currentPattern.SetValue("KadenKang");
19            Console.WriteLine("After using the SetValue, the TextBox value is '{0}'", currentPattern.Current.Value);
20            
21        }
22
23        /// <summary>
24        /// Get the automation elemention of current form.
25        /// </summary>
26        /// <param name="processId">Process Id</param>
27        /// <returns>Target element</returns>
28        public static AutomationElement FindWindowByProcessId(int processId)
29        {
30            AutomationElement targetWindow = null;
31            int count = 0;
32            try
33            {
34                Process p = Process.GetProcessById(processId);
35                targetWindow = AutomationElement.FromHandle(p.MainWindowHandle);
36                return targetWindow;
37            }
38            catch (Exception ex)
39            {
40                count++;
41                StringBuilder sb = new StringBuilder();
42                string message = sb.AppendLine(string.Format("Target window is not existing.try #{0}", count)).ToString();
43                if (count > 5)
44                {
45                    throw new InvalidProgramException(message, ex);
46                }
47                else
48                {
49                    return FindWindowByProcessId(processId);
50                }
51            }
52        }
53
54        /// <summary>
55        /// Get the automation element by automation Id.
56        /// </summary>
57        /// <param name="windowName">Window name</param>
58        /// <param name="automationId">Control automation Id</param>
59        /// <returns>Automatin element searched by automation Id</returns>
60        public static AutomationElement FindElementById(int processId, string automationId)
61        {
62            AutomationElement aeForm = FindWindowByProcessId(processId);
63            AutomationElement tarFindElement = aeForm.FindFirst(TreeScope.Descendants,
64            new PropertyCondition(AutomationElement.AutomationIdProperty, automationId));
65            return tarFindElement;
66        }
67
68        ValuePattern helper
87    }
88}
89

下面的代码是xaml设计:


1<Window x:Class="WpfApp.Window1"
2    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4    Title="Window1" Height="219" Width="353">
5    <Grid>
6        <TextBox Height="23" Margin="50,20,160,0" Name="textBox1" VerticalAlignment="Top" MaxLength="5">textBox text</TextBox>
7    </Grid>
8</Window>
9

     本文通过简单的实例介绍了UI Automation中的ValuePattern及其使用方法。

使用UI Automation实现自动化测试--4.5 (WindowPattern)

WindowPattern 控件模式用于支持在传统的 图形用户界面 (GUI) 内提供基于基本窗口的功能的控件。必须实现此控件模式的控件的示例包括顶级应用程序窗口、多文档界面 (MDI) 子窗口、大小可调的拆分窗格控件、模式对话框以及气球状帮助窗口。可以使用WindowPattern来对window进行操作,例如验证window是否激活,是否最大化、最小化、正常模式以及关闭window等。
     下面的代码演示了WindowPattern的使用方法: 


 1
using System;

 2
using System.Text;

 3
using System.Diagnostics;

 4
using System.Threading;

 5
using System.Windows.Automation;

 6

 7
namespace UIATest

 8
{

 9
    class Program

10
    {

11
        static void Main(string[] args)

12
        {

13
            Process process = Process.Start(@"F:\CSharpDotNet\AutomationTest\ATP\WpfApp\bin\Debug\WpfApp.exe");

14
            int processId = process.Id;

15
            AutomationElement element = FindWindowByProcessId(processId);

16
            WindowPattern currentPattern = GetWindowPattern(element);

17
            

18
            //Set window visual state to Maximized

19
            currentPattern.SetWindowVisualState(WindowVisualState.Maximized);

20
            Thread.Sleep(1000);

21

22
            //Set window visual state to Normal

23
            currentPattern.SetWindowVisualState(WindowVisualState.Normal);

24
            Thread.Sleep(1000);

25

26
            //Set window visual state to Minimized

27
            currentPattern.SetWindowVisualState(WindowVisualState.Minimized);

28
            

29
            //Close window

30
            currentPattern.Close();            

31
        }

32

33
        /// <summary>

34
        /// Get the automation elemention of current form.

35
        /// </summary>

36
        /// <param name="processId">Process Id</param>

37
        /// <returns>Target element</returns>

38
        public static AutomationElement FindWindowByProcessId(int processId)

39
        {

40
            AutomationElement targetWindow = null;

41
            int count = 0;

42
            try

43
            {

44
                Process p = Process.GetProcessById(processId);

45
                targetWindow = AutomationElement.FromHandle(p.MainWindowHandle);

46
                return targetWindow;

47
            }

48
            catch (Exception ex)

49
            {

50
                count++;

51
                StringBuilder sb = new StringBuilder();

52
                string message = sb.AppendLine(string.Format("Target window is not existing.try #{0}", count)).ToString();

53
                if (count > 5)

54
                {

55
                    throw new InvalidProgramException(message, ex);

56
                }

57
                else

58
                {

59
                    return FindWindowByProcessId(processId);

60
                }

61
            }

62
        }

63

64
        WindowPattern helper

83
    }

84
}

使用UI Automation实现自动化测试--4.6.1 (SelectionItemPattern)

SelectionItemPattern

支持SelectionItemPattern的控件有ListView、ListBox、RadioButton、GridView等。

  1. 1.         SelectionItemPattern的三个重要方法:
  2. 1.         AddToSelection:将当前元素添加到所选项的集合。
  3. 2.         RemoveFromSelection: 从选定项的集合中移除当前元素。
  4. 3.         Select: 取消所有已选中的项,然后选择当前元素。
  5. 2.         SelectionItemPattern的Current属性可通过Current属性的IsSelected属性来判断AutomationElement是否被selected.

     如下代码演示了使用SelectionItemPattern来操作RadioButton控件。


 1using System;
 2using System.Text;
 3using System.Diagnostics;
 4using System.Threading;
 5using System.Windows.Automation;
 6
 7namespace UIATest
 8{
 9    class Program
10    {
11        static void Main(string[] args)
12        {
13            Process process = Process.Start(@"F:\CSharpDotNet\AutomationTest\ATP\WpfApp\bin\Debug\WpfApp.exe");
14            int processId = process.Id;
15
16            AutomationElement element = FindElementById(processId, "radioButton1");
17            SelectionItemPattern selectionItemPattern = GetSelectionItemPattern(element);
18            selectionItemPattern.Select();
19        }
20
21        /// <summary>
22        /// Get the automation elemention of current form.
23        /// </summary>
24        /// <param name="processId">Process Id</param>
25        /// <returns>Target element</returns>
26        public static AutomationElement FindWindowByProcessId(int processId)
27        {
28            AutomationElement targetWindow = null;
29            int count = 0;
30            try
31            {
32                Process p = Process.GetProcessById(processId);
33                targetWindow = AutomationElement.FromHandle(p.MainWindowHandle);
34                return targetWindow;
35            }
36            catch (Exception ex)
37            {
38                count++;
39                StringBuilder sb = new StringBuilder();
40                string message = sb.AppendLine(string.Format("Target window is not existing.try #{0}", count)).ToString();
41                if (count > 5)
42                {
43                    throw new InvalidProgramException(message, ex);
44                }
45                else
46                {
47                    return FindWindowByProcessId(processId);
48                }
49            }
50        }
51
52
53        /// <summary>
54        /// Get the automation element by automation Id.
55        /// </summary>
56        /// <param name="windowName">Window name</param>
57        /// <param name="automationId">Control automation Id</param>
58        /// <returns>Automatin element searched by automation Id</returns>
59        public static AutomationElement FindElementById(int processId, string automationId)
60        {
61            AutomationElement aeForm = FindWindowByProcessId(processId);
62            AutomationElement tarFindElement = aeForm.FindFirst(TreeScope.Descendants,
63            new PropertyCondition(AutomationElement.AutomationIdProperty, automationId));
64            return tarFindElement;
65        }
66
67        SelectItemPattern
86    }
87}
88

     以下代码为XAML:


1<Window x:Class="WpfApp.Window1"
2    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4    Title="Window1" Height="219" Width="353">
5    <Grid>
6        <RadioButton Height="16" HorizontalAlignment="Right" Margin="0,46,10,0" Name="radioButton1" VerticalAlignment="Top" Width="120">RadioButton</RadioButton>
7    </Grid>
8</Window>
9

    本文简单介绍了SelectionItemPattern以及使用SelectionItemPattern来操作RadioButton。

使用UI Automation实现自动化测试--4.6.2 (SelectItemPattern Demo)

 如下代码演示了使用SelectionItemPattern来实现listview item 的多选操作:


  1
using System;

  2
using System.Text;

  3
using System.Diagnostics;

  4
using System.Threading;

  5
using System.Windows.Automation;

  6

  7
namespace UIATest

  8
{

  9
    class Program

 10
    {

 11
        static void Main(string[] args)

 12
        {

 13
            Process process = Process.Start(@"F:\CSharpDotNet\AutomationTest\ATP\WpfApp\bin\Debug\WpfApp.exe");

 14
            int processId = process.Id;

 15

 16
            Thread.Sleep(1000);

 17
            MutlSelect(new int[] { 0, 1 }, processId, false);

 18
        }

 19

 20
        /// <summary>

 21
        /// Get the automation elemention of current form.

 22
        /// </summary>

 23
        /// <param name="processId">Process Id</param>

 24
        /// <returns>Target element</returns>

 25
        public static AutomationElement FindWindowByProcessId(int processId)

 26
        {

 27
            AutomationElement targetWindow = null;

 28
            int count = 0;

 29
            try

 30
            {

 31
                Process p = Process.GetProcessById(processId);

 32
                targetWindow = AutomationElement.FromHandle(p.MainWindowHandle);

 33
                return targetWindow;

 34
            }

 35
            catch (Exception ex)

 36
            {

 37
                count++;

 38
                StringBuilder sb = new StringBuilder();

 39
                string message = sb.AppendLine(string.Format("Target window is not existing.try #{0}", count)).ToString();

 40
                if (count > 5)

 41
                {

 42
                    throw new InvalidProgramException(message, ex);

 43
                }

 44
                else

 45
                {

 46
                    return FindWindowByProcessId(processId);

 47
                }

 48
            }

 49
        }

 50

 51

 52
        /// <summary>

 53
        /// Get the automation element by automation Id.

 54
        /// </summary>

 55
        /// <param name="windowName">Window name</param>

 56
        /// <param name="automationId">Control automation Id</param>

 57
        /// <returns>Automatin element searched by automation Id</returns>

 58
        public static AutomationElement FindElementById(int processId, string automationId)

 59
        {

 60
            AutomationElement aeForm = FindWindowByProcessId(processId);

 61
            AutomationElement tarFindElement = aeForm.FindFirst(TreeScope.Descendants,

 62
            new PropertyCondition(AutomationElement.AutomationIdProperty, automationId));

 63
            return tarFindElement;

 64
        }

 65
        

 66
        /// <summary>

 67
        /// Bulk select the list item

 68
        /// </summary>

 69
        /// <param name="indexes">List item index collection</param>

 70
        /// <param name="processId">Application process Id</param>

 71
        /// <param name="isSelectAll">Is select all or not</param>

 72
        public static void MutlSelect(int[] indexes, int processId, bool isSelectAll)

 73
        {

 74
            AutomationElement targetElement = FindElementById(processId, "listView1");

 75

 76
            AutomationElementCollection rows =

 77
                targetElement.FindAll(TreeScope.Descendants,

 78
                new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.ListItem));

 79

 80
            object multiSelect;

 81

 82
            if (isSelectAll)

 83
            {

 84
                for (int i = 1; i < rows.Count - 1; i++)

 85
                {

 86
                    if (rows[i].TryGetCurrentPattern(SelectionItemPattern.Pattern, out multiSelect))

 87
                    {

 88
                        (multiSelect as SelectionItemPattern).AddToSelection();

 89
                    }

 90
                }

 91
            }

 92
            else

 93
            {

 94
                if (indexes.Length > 0)

 95
                {

 96
                    for (int j = 0; j < indexes.Length; j++)

 97
                    {

 98
                        int tempIndex = indexes[j];

 99
                        if (rows[tempIndex].TryGetCurrentPattern(SelectionItemPattern.Pattern, out multiSelect))

100
                        {

101
                            (multiSelect as SelectionItemPattern).AddToSelection();

102
                        }

103
                    }

104
                }

105
            }

106
        }

107

108
        SelectItemPattern

127
    }

128
}

      如下代码为对应的XAML:


 1
<Window x:Class="WpfApp.Window2"

 2
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

 3
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

 4
    Title="Window2" Height="412" Width="585">

 5
    <Grid>

 6
        <ListView Margin="2,97,0,163" Name="listView1">

 7
            <ListViewItem>Kaden</ListViewItem>

 8
            <ListViewItem>KangYi</ListViewItem>

 9
            <ListViewItem>John</ListViewItem>

10
        </ListView>

11
    </Grid>

12
</Window>

13

使用UI Automation实现自动化测试--4.7 (TogglePattern)

TogglePattern

支持TogglePattern的控件有CheckBox,TreeView中的button控件等。

  1. 1.       TogglePattern的方法

Toggle方法用于操作可以循环通过的一组状态并在设置后保持某种状态。

  1. 2.       TogglePattern属性

Current属性中的ToggleState有如下三种状态:

  1. 1.         On
  2. 2.         Off
  3. 3.         Indeterminate

    如下代码演示了使用TogglePattern来操作CheckBox控件。


 1using System;
 2using System.Text;
 3using System.Diagnostics;
 4using System.Threading;
 5using System.Windows.Automation;
 6
 7namespace UIATest
 8{
 9    class Program
10    {
11        static void Main(string[] args)
12        {
13            Process process = Process.Start(@"F:\CSharpDotNet\AutomationTest\ATP\WpfApp\bin\Debug\WpfApp.exe");
14            int processId = process.Id;
15
16            Thread.Sleep(1000);
17            AutomationElement element = FindElementById(processId, "checkBox1");
18            TogglePattern togglePattern = GetTogglePattern(element);
19            togglePattern.Toggle();
20        }
21
22        /// <summary>
23        /// Get the automation elemention of current form.
24        /// </summary>
25        /// <param name="processId">Process Id</param>
26        /// <returns>Target element</returns>
27        public static AutomationElement FindWindowByProcessId(int processId)
28        {
29            AutomationElement targetWindow = null;
30            int count = 0;
31            try
32            {
33                Process p = Process.GetProcessById(processId);
34                targetWindow = AutomationElement.FromHandle(p.MainWindowHandle);
35                return targetWindow;
36            }
37            catch (Exception ex)
38            {
39                count++;
40                StringBuilder sb = new StringBuilder();
41                string message = sb.AppendLine(string.Format("Target window is not existing.try #{0}", count)).ToString();
42                if (count > 5)
43                {
44                    throw new InvalidProgramException(message, ex);
45                }
46                else
47                {
48                    return FindWindowByProcessId(processId);
49                }
50            }
51        }
52
53        /// <summary>
54        /// Get the automation element by automation Id.
55        /// </summary>
56        /// <param name="windowName">Window name</param>
57        /// <param name="automationId">Control automation Id</param>
58        /// <returns>Automatin element searched by automation Id</returns>
59        public static AutomationElement FindElementById(int processId, string automationId)
60        {
61            AutomationElement aeForm = FindWindowByProcessId(processId);
62            AutomationElement tarFindElement = aeForm.FindFirst(TreeScope.Descendants,
63            new PropertyCondition(AutomationElement.AutomationIdProperty, automationId));
64            return tarFindElement;
65        }
66
67        TogglePattern helper
83    }
84}
85

     如下代码为对应的XAML:


1<Window x:Class="WpfApp.Window1"
2    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4    Title="Window1" Height="219" Width="353">
5    <Grid>
6        <CheckBox HorizontalAlignment="Right" Margin="0,75,10,89" Name="checkBox1" Width="120">CheckBox</CheckBox>
7    </Grid>
8</Window>

使用UI Automation实现自动化测试--4.8 (GridPattern)

GridPattern

支持GridPattern的最常见的控件为GridView, 在WPF中使用ListView和GridView组合即可得到相应的GridView。

GridPattern的方法

GetItem:此方法有两个参数,即DataGrid的Row和Column。

通过GridPattern的GetItem方法可以获取DataGrid中的某个确定的单元格,进而对单元进行操作。

对单元格的操作主要有以下几个方面:

  1. 1.       编辑单元个中的数据。
  2. 2.       获取单元格中的数据。
  3. 3.       获取单元格中嵌套的AutomationElement(一般使用与自定义控件中)。

GridPattern的属性

GridPattern的Current属性中有如下两个属性:

  1. 1.       RowCount属性:GridPattern二维表格的行数。
  2. 2.       ColumnCount属性:GridPattern二维表格列数。

下面我们通过一个实例来演示自动化测试中如何使用GridPattern来测试GridView的方法:


 1using System;
 2using System.Text;
 3using System.Diagnostics;
 4using System.Threading;
 5using System.Windows.Automation;
 6
 7namespace UIATest
 8{
 9    class Program
10    {
11        static void Main(string[] args)
12        {
13            Process process = Process.Start(@"F:\CSharpDotNet\AutomationTest\ATP\WpfApp\bin\Debug\WpfApp.exe");
14            int processId = process.Id;
15            Thread.Sleep(1000);
16
17            GridPattern Test
30        }
31
32        /// <summary>
33        /// Get the automation elemention of current form.
34        /// </summary>
35        /// <param name="processId">Process Id</param>
36        /// <returns>Target element</returns>
37        public static AutomationElement FindWindowByProcessId(int processId)
38        {
39            AutomationElement targetWindow = null;
40            int count = 0;
41            try
42            {
43                Process p = Process.GetProcessById(processId);
44                targetWindow = AutomationElement.FromHandle(p.MainWindowHandle);
45                return targetWindow;
46            }
47            catch (Exception ex)
48            {
49                count++;
50                StringBuilder sb = new StringBuilder();
51                string message = sb.AppendLine(string.Format("Target window is not existing.try #{0}", count)).ToString();
52                if (count > 5)
53                {
54                    throw new InvalidProgramException(message, ex);
55                }
56                else
57                {
58                    return FindWindowByProcessId(processId);
59                }
60            }
61        }
62
63        /// <summary>
64        /// Get the automation element by automation Id.
65        /// </summary>
66        /// <param name="windowName">Window name</param>
67        /// <param name="automationId">Control automation Id</param>
68        /// <returns>Automatin element searched by automation Id</returns>
69        public static AutomationElement FindElementById(int processId, string automationId)
70        {
71            AutomationElement aeForm = FindWindowByProcessId(processId);
72            AutomationElement tarFindElement = aeForm.FindFirst(TreeScope.Descendants,
73            new PropertyCondition(AutomationElement.AutomationIdProperty, automationId));
74            return tarFindElement;
75        }
76
77        GridPattern helper
95    }
96}
97

    对应的XAML代码如下:


 1<Window x:Class="WpfApp.GridView"
 2    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 3    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 4    Title="GridView" Height="426" Width="558">
 5    <Grid>
 6        <!--将鼠标放在方框的边缘点击就会产生相应的分割线生成Grid.RowDefinitions-->
 7        <Grid.RowDefinitions>
 8            <!--Auto,实际作用就是取实际控件所需的最小值;值为*或N*,实际作用就是取尽可能大的值;数字,绝对尺寸-->
 9            <RowDefinition Height="*" />
10            <RowDefinition Height="auto" MinHeight="95" />
11            <RowDefinition Height="22" />
12        </Grid.RowDefinitions>
13        <ListView Name="listview1" MinWidth="280" Grid.RowSpan="2" MouseMove="listview1_MouseMove">
14            <ListView.View>
15                <GridView x:Name="gridView1">
16                    <GridViewColumn Header="EmployeeID" DisplayMemberBinding="{Binding Path=EmployeeID}"></GridViewColumn>
17                    <GridViewColumn Header="FirstName" DisplayMemberBinding="{Binding Path=FirstName}"></GridViewColumn>
18                    <GridViewColumn Header="LastName" DisplayMemberBinding="{Binding Path=LastName}"></GridViewColumn>
19                    <GridViewColumn Header="Address" DisplayMemberBinding="{Binding Path=Address}"></GridViewColumn>
20                </GridView>
21            </ListView.View>
22        </ListView>
23    </Grid>
24
25</Window>
26

    GridView窗体后台代码如下:


 1using System;
 2using System.Collections.Generic;
 3using System.Linq;
 4using System.Text;
 5using System.Windows;
 6using System.Windows.Controls;
 7using System.Windows.Data;
 8using System.Windows.Documents;
 9using System.Windows.Input;
10using System.Windows.Media;
11using System.Windows.Media.Imaging;
12using System.Windows.Shapes;
13using System.Data.SqlClient;
14using System.Data;
15
16namespace WpfApp
17{
18    /// <summary>
19    /// Interaction logic for GridView.xaml
20    /// </summary>
21    public partial class GridView : Window
22    {
23        public GridView()
24        {
25            InitializeComponent();
26            getData();
27        }
28        SqlDataAdapter sda;
29        DataTable dt;
30        void getData()
31        {
32            //Northwind database download path:http://download.csdn.net/down/845087/beyondchina123
33            //init sqlconnection
34            SqlConnectionStringBuilder connbuilder = new SqlConnectionStringBuilder();
35            connbuilder.DataSource = ".";//本地服务器
36            connbuilder.IntegratedSecurity = true;//Windows集成验证
37            connbuilder.InitialCatalog = "Northwind";//数据库为Northwind
38            SqlConnection conn = new SqlConnection(connbuilder.ConnectionString);
39            sda = new SqlDataAdapter("select EmployeeID,FirstName,LastName,Address from Employees ", conn);
40            SqlCommandBuilder commbuilder = new SqlCommandBuilder(sda);
41            dt = new DataTable();
42            sda.Fill(dt);
43            listview1.ItemsSource = dt.DefaultView;
44        }
45      }
46}
47
48

     本文主要简单介绍了GridPattern以及GridPattern在测试中是使用方法。

使用UI Automation实现自动化测试--4.9 (ScrollPattern)

ScrollPattern

ScrollPattern是用来操作控件的滚动条,目前支持ScrollPattern的控件有ListBox,listView,GridView,TreeView.

ScrollPattern主要方法

  1. 1.         Scroll 水平和垂直滚动内容区域的可见区域滚动, Scroll有两个参数,其类型为ScrollAmount枚举类型。
  2. 2.         ScrollHorizontal 按指定的 ScrollAmount 水平滚动内容区域的当前可见区域滚动。
  3. 3.         ScrollVertical 按指定的 ScrollAmount 垂直滚动内容区域的当前可见区域滚动。

ScrollPattern属性

  1. VerticallyScrollable 属性用于判定是否可以垂直滚动。
  2. HorizontallyScrollable 属性用于判定是否可以水平滚动。
  3. HorizontalScrollPercent 获取当前水平滚动条的位置。
  4. VerticalScrollPercent 获取当前垂直滚动条的位置。

下面我们通过一个实例来演示自动化测试中如何使用ScrollPattern来测试GridView中滚动条的方法:


  1using System;
  2using System.Text;
  3using System.Diagnostics;
  4using System.Threading;
  5using System.Windows.Automation;
  6
  7namespace UIATest
  8{
  9    class Program
 10    {
 11        static void Main(string[] args)
 12        {
 13            Process process = Process.Start(@"F:\CSharpDotNet\AutomationTest\ATP\WpfApp\bin\Debug\WpfApp.exe");
 14            int processId = process.Id;
 15            Thread.Sleep(1000);
 16
 17            ScrollPattern
 31            
 32        }
 33
 34        /// <summary>
 35        /// Get the automation elemention of current form.
 36        /// </summary>
 37        /// <param name="processId">Process Id</param>
 38        /// <returns>Target element</returns>
 39        public static AutomationElement FindWindowByProcessId(int processId)
 40        {
 41            AutomationElement targetWindow = null;
 42            int count = 0;
 43            try
 44            {
 45                Process p = Process.GetProcessById(processId);
 46                targetWindow = AutomationElement.FromHandle(p.MainWindowHandle);
 47                return targetWindow;
 48            }
 49            catch (Exception ex)
 50            {
 51                count++;
 52                StringBuilder sb = new StringBuilder();
 53                string message = sb.AppendLine(string.Format("Target window is not existing.try #{0}", count)).ToString();
 54                if (count > 5)
 55                {
 56                    throw new InvalidProgramException(message, ex);
 57                }
 58                else
 59                {
 60                    return FindWindowByProcessId(processId);
 61                }
 62            }
 63        }
 64
 65
 66        /// <summary>
 67        /// Get the automation element by automation Id.
 68        /// </summary>
 69        /// <param name="windowName">Window name</param>
 70        /// <param name="automationId">Control automation Id</param>
 71        /// <returns>Automatin element searched by automation Id</returns>
 72        public static AutomationElement FindElementById(int processId, string automationId)
 73        {
 74            AutomationElement aeForm = FindWindowByProcessId(processId);
 75            AutomationElement tarFindElement = aeForm.FindFirst(TreeScope.Descendants,
 76            new PropertyCondition(AutomationElement.AutomationIdProperty, automationId));
 77            return tarFindElement;
 78        }
 79
 80        GetScrollPattern helper
 98    }
 99}
100

   XAML源码:


 1<Window x:Class="WpfApp.GridView"
 2    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 3    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 4    Title="GridView" Height="280" Width="467">
 5    <Grid>
 6        <!--将鼠标放在方框的边缘点击就会产生相应的分割线生成Grid.RowDefinitions-->
 7        <Grid.RowDefinitions>
 8            <!--Auto,实际作用就是取实际控件所需的最小值;值为*或N*,实际作用就是取尽可能大的值;数字,绝对尺寸-->
 9            <RowDefinition Height="*" />
10            <RowDefinition Height="auto" MinHeight="95" />
11            <RowDefinition Height="22" />
12        </Grid.RowDefinitions>
13        <ListView Name="listview1" MinWidth="280" Grid.RowSpan="2" MouseMove="listview1_MouseMove">
14            <ListView.View>
15                <GridView x:Name="gridView1">
16                    <GridViewColumn Header="EmployeeID" DisplayMemberBinding="{Binding Path=EmployeeID}"></GridViewColumn>
17                    <GridViewColumn Header="FirstName" DisplayMemberBinding="{Binding Path=FirstName}"></GridViewColumn>
18                    <GridViewColumn Header="LastName" DisplayMemberBinding="{Binding Path=LastName}"></GridViewColumn>
19                    <GridViewColumn Header="Address" DisplayMemberBinding="{Binding Path=Address}"></GridViewColumn>
20                </GridView>
21            </ListView.View>
22        </ListView>
23        <!--Grid.Row="1"用来设置WrapPanel及Button应该在父容器的什么位置-->
24    </Grid>
25
26</Window>

       后台CS源码:


 1using System;
 2using System.Collections.Generic;
 3using System.Linq;
 4using System.Text;
 5using System.Windows;
 6using System.Windows.Controls;
 7using System.Windows.Data;
 8using System.Windows.Documents;
 9using System.Windows.Input;
10using System.Windows.Media;
11using System.Windows.Media.Imaging;
12using System.Windows.Shapes;
13using System.Data.SqlClient;
14using System.Data;
15
16namespace WpfApp
17{
18    /// <summary>
19    /// Interaction logic for GridView.xaml
20    /// </summary>
21    public partial class GridView : Window
22    {
23        public GridView()
24        {
25            InitializeComponent();
26            getData();
27        }
28        SqlDataAdapter sda;
29        DataTable dt;
30        void getData()
31        {
32            //init sqlconnection
33            SqlConnectionStringBuilder connbuilder = new SqlConnectionStringBuilder();
34            connbuilder.DataSource = ".";//本地服务器
35            connbuilder.IntegratedSecurity = true;//Windows集成验证
36            connbuilder.InitialCatalog = "TestDB";//数据库为Northwind
37            SqlConnection conn = new SqlConnection(connbuilder.ConnectionString);
38            sda = new SqlDataAdapter("select EmployeeID,FirstName,LastName,Address from Employees ", conn);
39            SqlCommandBuilder commbuilder = new SqlCommandBuilder(sda);
40            //sda.UpdateCommand = commbuilder.GetUpdateCommand();
41            dt = new DataTable();
42            //sda.AcceptChangesDuringUpdate = true;
43            sda.Fill(dt);
44            listview1.ItemsSource = dt.DefaultView;
45        }
46    }
47}
48
49

       数据库及数据库表源码:


 1USE [master]
 2GO
 3/****** Object:  Database TestDB    Script Date: 10/17/2009 16:08:09 ******/
 4IF  EXISTS (SELECT name FROM sys.databases WHERE name = N'TestDB')
 5DROP DATABASE [TestDB]
 6CREATE DATABASE TestDB ON  PRIMARY 
 7( NAME = N'TestDB', FILENAME = N'C:\TestDB.mdf' , SIZE = 2688KB , MAXSIZE = UNLIMITED, FILEGROWTH = 80KB )
 8 LOG ON 
 9( NAME = N'TestDB_log', FILENAME = N'C:\TestDB.ldf' , SIZE = 1024KB , MAXSIZE = UNLIMITED, FILEGROWTH = 10%)
10GO
11
12use TestDB
13
14CREATE TABLE [dbo].[Employees](
15    [EmployeeID] [int] IDENTITY(1,1) primary key NOT NULL,
16    [LastName] [varchar](20) NOT NULL,
17    [FirstName] [varchar](10) NOT NULL,
18    [Address] [varchar](60) NULL
19) 
20
21GO
22truncate table employees
23declare @i int
24set @i = 1
25while @i<25
26begin
27
28insert into Employees
29(
30   LastName,
31   FirstName,
32   [Address]
33) 
34values
35('Kaden'+cast(@i as varchar), 'Kang'+cast(@i as varchar), 'Nanjing, Jiangsu, China'+cast(@i as varchar))
36set @i=@i+1
37end
38
39

        本文简单介绍了ScrollPattern以及使用ScrollPattern来操作垂直水平滚动条。


http://chatgpt.dhexx.cn/article/JGxwCsBk.shtml

相关文章

Python UI自动化 编程(一) UIAutomation

Python UI自动化 编程 第一章 Python UI自动化 编程入门之打开文件夹双击文件 文章目录 Python UI自动化 编程前言一、什么是Python UI自动化 编程二、环境说明1、Python环境&#xff1a;Python 3.82、IDE&#xff1a; Pycharm3、使用的库&#xff1a;UIAutomation 三、使用步…

【python】UI自动化-uiautomation

UI自动化-uiautomation 0- 前言1- inspect2- uiautomation3- 【实战】RustDesk软件自动 安装、指定服务器信息4- 参考文章 0- 前言 做应用程序自动点击的记录&#xff0c;暂不完整&#xff0c;仅供参考。参考多位大佬文章&#xff0c;链接在后面涉及工具 inspect【应用程序元素…

CAD 双击实体事件

CAD本身为我们提供的双击事件的设置。工具-工作空间-自定义...打开用户自定界面 窗体内找到双击动作。在双击动作下我们可以看到CAD自带的所有实体 例如我们在双击三维实体时自定义一个事件。那么我们就选中三维实体-快捷特性。在右侧特性里编辑宏内容。以下是系统彼带的宏$M$(…

深入探索透视投影变换(续)

-潘宏 -2009.4.14 -本人水平有限&#xff0c;疏忽错误在所难免&#xff0c;还请各位数学高手、编程高手不吝赐教 -email: popyynetease.com -B站专栏&#xff1a; https://b23.tv/oWsl6PD 在上一篇文章中我们讨论了透视投影变换的原理&#xff0c;分析了OpenGL所使用的透视…

凯文·凯利:AI将改变一切设计工作

每一项新技术诞生之初都会引发新一轮科技恐慌周期&#xff0c;近期大火的AI生成艺术更是如此。连线杂志创始主编、知名科技思想家凯文凯利&#xff08;Kevin Kelly&#xff09;在6个月重度使用之后认为&#xff0c;这次AI进展的确是一次令人震惊的突破。但是&#xff0c;它不会…

鼠标双击退出应用程序简单实现

文章目录 Android 简单模拟鼠标双击退出应用程序&#xff0c;利用Toast提示“再点一次退出”使用Toast鼠标单击提示信息鼠标双击实现退出系统 Android 简单模拟鼠标双击退出应用程序&#xff0c;利用Toast提示“再点一次退出” 使用Toast // 参数&#xff1a;当前上下文环境&…

如何用JavaScript完美地区分双击和单击事件

通过一个悬浮球交互功能的案例来阐述问题&#xff0c;以及解决办法。 实现效果 类似微信里的悬浮窗效果&#xff0c;苹果手机的悬浮球功能效果 1.可以点击拖动&#xff0c;然后吸附在窗口边缘2.点击悬浮球&#xff0c;可以跳转界面&#xff0c;或者更改悬浮球的形态准备 1.移…

单机显示、双击隐藏;事件绑定、单击div、双击div、删除事件;元素显示、隐藏、交替; 向上收缩、向下展开、交替;淡入淡出

单机显示、双击隐藏 <style>div {width: 500px;height: 200px;background-color: green;display: none;} </style> <body><button id"btn">单击显示&#xff0c;双击隐藏</button><br><br><div> </div&…

干货分享 | UE游戏鼠标双击判定

UE虚幻引擎对于游戏开发者来说都不陌生&#xff0c;市面上有47%主机游戏使用虚幻引擎开发游戏。作为是一款游戏的核心动力&#xff0c;它的功能十分完善&#xff0c;囊括了场景制作、灯光渲染、动作镜头、粒子特效、材质蓝图等。本文介绍了虚幻引擎游戏开发过程中游戏鼠标双击判…

鼠标单击变双击问题

解决此问题可以从硬件和软件两方面思考角度入手:我们先把鼠标插在别人的机器上使用,如果没发现问题可能是软件问题,若发现同样的问题则可能是硬件方面的问题。 软件方面:(1)病毒导致将杀毒软件病毒库更新至最新版,全盘扫描。 (2)鼠标属性设置不当我们打开控制面板-&…

鼠标双击事件

随时随地阅读更多技术实战干货&#xff0c;获取项目源码、学习资料&#xff0c;请关注源代码社区公众号(ydmsq666) java中没有给出鼠标双击事件&#xff0c;虽然可以通过事件源e.getClickCount()2来判断鼠标点击次数&#xff0c;但是执行双击事件的同时也执行了单击事件&#x…

关于双击与单击事件冲突解决方案

有时候会要需求要求&#xff0c;比如附件&#xff0c;单击查看详情&#xff0c;双击下载文件时遇到的双击单击事件同时绑定一个节点。 比如单击click&#xff0c;dlbclick同时绑定时&#xff0c;双击会同时触发&#xff0c;而且click会触发两次。单用click来处理双击单击同时存…

TRUE PARTNER迎来戴维斯双击,资产规模业绩双增长

配图来自Canva可画 2020年可谓是黑天鹅乱舞的一年&#xff0c;新冠疫情肆虐全球&#xff1b;原油危机引发的资本市场动荡&#xff1b;地缘政治冲突以及美国大选&#xff0c;市场处于时不时来一波的上蹿下跳的状态当中。 在资本市场波动加剧的大环境中&#xff0c;有这样一家奇…

慧择业务布局成效明显,戴维斯双击可期

“没有一个冬天不会过去&#xff0c;没有一个春天不会到来”。 过去的一年&#xff0c;美股市场波折不断&#xff0c;尤其是2020年3月份的4次熔断&#xff0c;让股神巴菲特都惊呼“活久见”。 过去的一年&#xff0c;美股市场惊喜不断&#xff0c;道琼斯指数更是在2020年11月创…

流动性持续改善,佳源国际迎来“戴维斯双击”?

随着上半年密集的救市政策出台&#xff0c;房地产行业迎来触底回暖。 5月&#xff0c;央行以不低于市场报价利率20个基点调整首套房贷款利率下限&#xff0c;这也让当前金融环境在近几年处于较为宽松的阶段。 据克而瑞研究中心观点&#xff0c;因冲刺年中业绩&#xff0c;房企…

湖人詹姆斯 戴维斯 拉塞尔三人合体就赢!

湖人主力詹姆斯&#xff08;LeBron James&#xff09;球星成为NBA新历史得分王后&#xff0c;连3战因伤缺席&#xff0c;今天主场对抗鹈鹕终于回归&#xff0c;和戴维斯&#xff08;Anthony Davis&#xff09;、拉塞尔&#xff08;DAngelo Russell&#xff09;三人连线&#xf…

九龙证券|游戏板块或继续迎来业绩估值“戴维斯双击”

机构指出&#xff0c;AIGC技术及产品现在已在游戏职业有部分使用&#xff0c;中长期来看&#xff0c;对游戏制作的降本增效、内容质量进步有较强的促进作用&#xff1b;当前游戏版号常态化发放&#xff0c;政策端不确定性降低&#xff0c;预计产品周期是成绩的要害驱动&#xf…

戴维斯双击背后的故事 - 读《戴维斯王朝》

一、序言 作为一个对炒股知识孤陋寡闻的新手&#xff0c;我最近才听说「戴维斯双击」&#xff0c;于是买了《戴维斯王朝》了解了一下戴维斯本人以及他的成功故事。看完书后&#xff0c;我感觉戴维斯本人还真算是一段传奇经历。 戴维斯的投资回报率和巴菲特对等&#xff0c;他投…

科普一下,什么是戴维斯双击和戴维斯双杀?

创业板受到多重利空压制而大跌&#xff0c;上证也受到拖累&#xff0c;只有上证50小幅翻红。创业板依然是下跌趋势&#xff0c;不要瞎猜底部&#xff0c;更不要轻易抄底&#xff0c;要以均线为准&#xff0c;反弹站上5日线才有短线机会。主板部分板块仍然是处于上升趋势&#x…

股票策略 —— 戴维斯双击

1、策略概述 这里的戴维斯是美国的一个投资大师&#xff0c;38 岁才开始投资生涯&#xff0c;初始资金 5 万美元&#xff0c;最终财富达到 9 亿美元&#xff0c;并登上福布斯400 富豪榜。他投资策略中的选股的要点是良好的管理、持续增长及低估值。 后来基于这两个原则&#x…