using System;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Threading;
using System.Windows.Automation;
namespace TestProject
{
/// <summary>
/// UI 자동화 헬퍼
/// </summary>
public static class UIAutomationHelper
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 엘리먼트 탐색 타임아웃 초 카운트
/// </summary>
private const int ELEMENT_SEARCH_TIMEOUT_SECOND_COUNT = 10;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Public
#region 애플리케이션 실행하기 - ExecuteApplication(filePath, argumentList)
/// <summary>
/// 애플리케이션 실행하기
/// </summary>
/// <param name="filePath">파일 경로</param>
/// <param name="argumentList">인자 리스트</param>
/// <returns>자동화 엘리먼트</returns>
public static AutomationElement ExecuteApplication(string filePath, string argumentList)
{
Process process = new Process();
process.StartInfo.FileName = filePath;
process.StartInfo.Arguments = argumentList;
process.Start();
Thread.Sleep(2000);
return (AutomationElement.FromHandle(process.MainWindowHandle));
}
#endregion
#region 애플리케이션 실행하기 - ExecuteApplication(filePath)
/// <summary>
/// 애플리케이션 실행하기
/// </summary>
/// <param name="filePath">파일 경로</param>
/// <returns>자동화 엘리먼트</returns>
public static AutomationElement ExecuteApplication(string filePath)
{
return ExecuteApplication(filePath, string.Empty);
}
#endregion
#region 명칭으로 엘리먼트 컬렉션 구하기 - GetElementCollectionByName(windowElement, elementName)
/// <summary>
/// 명칭으로 엘리먼트 컬렉션 구하기
/// </summary>
/// <param name="windowElement">윈도우 엘리먼트</param>
/// <param name="elementName">엘리먼트명</param>
/// <returns>자동화 엘리먼트 컬렉션</returns>
public static AutomationElementCollection GetElementCollectionByName(AutomationElement windowElement, string elementName)
{
if(windowElement == null)
{
return null;
}
return GetElementCollection
(
windowElement,
new PropertyCondition(AutomationElement.NameProperty, elementName)
);
}
#endregion
#region 명칭으로 엘리먼트 구하기 - GetElementByName(windowElement, elementName)
/// <summary>
/// 명칭으로 엘리먼트 구하기
/// </summary>
/// <param name="windowElement">윈도우 엘리먼트</param>
/// <param name="elementName">엘리먼트명</param>
/// <returns>자동화 엘리먼트</returns>
public static AutomationElement GetElementByName(AutomationElement windowElement, string elementName)
{
if(windowElement == null)
{
return null;
}
return GetElement
(
windowElement,
new PropertyCondition(AutomationElement.NameProperty, elementName)
);
}
#endregion
#region ID로 엘리먼트 구하기 - GetElementByID(windowElement, elementID)
/// <summary>
/// ID로 엘리먼트 구하기
/// </summary>
/// <param name="windowElement">윈도우 엘리먼트</param>
/// <param name="elementID">엘리먼트 ID</param>
/// <returns>자동화 엘리먼트</returns>
public static AutomationElement GetElementByID(AutomationElement windowElement, string elementID)
{
if(windowElement == null)
{
return null;
}
return GetElement
(
windowElement,
new PropertyCondition(AutomationElement.AutomationIdProperty, elementID)
);
}
#endregion
#region 엘리먼트명 구하기 - GetElementName(windowElement, elementID)
/// <summary>
/// 엘리먼트명 구하기
/// </summary>
/// <param name="windowElement">윈도우 엘리먼트</param>
/// <param name="elementID">엘리먼트 ID</param>
/// <returns>엘리먼트명</returns>
public static string GetElementName(AutomationElement windowElement, string elementID)
{
return GetElementByID(windowElement, elementID).Current.Name;
}
#endregion
#region 엘리먼트 호출하기 - InvokeElement(windowElement, condition)
/// <summary>
/// 엘리먼트 호출하기
/// </summary>
/// <param name="windowElement">윈도우 엘리먼트</param>
/// <param name="condition">조건</param>
/// <returns>처리 결과</returns>
public static bool InvokeElement(AutomationElement windowElement, Condition condition)
{
if(windowElement == null)
{
return false;
}
AutomationElement element = GetElement(windowElement, condition);
if(element != null)
{
InvokePattern pattern = element.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern;
pattern.Invoke();
return true;
}
return false;
}
#endregion
#region 명칭으로 엘리먼트 호출하기 - InvokeElementByName(windowElement, elementName)
/// <summary>
/// 명칭으로 엘리먼트 호출하기
/// </summary>
/// <param name="windowElement">윈도우 엘리먼트</param>
/// <param name="elementName">엘리먼트명</param>
/// <returns>처리 결과</returns>
public static bool InvokeElementByName(AutomationElement windowElement, string elementName)
{
return InvokeElement
(
windowElement,
new PropertyCondition(AutomationElement.NameProperty, elementName)
);
}
#endregion
#region ID로 엘리먼트 호출하기 - InvokeElementByID(windowElement, elementID)
/// <summary>
/// ID로 엘리먼트 호출하기
/// </summary>
/// <param name="windowElement">윈도우 엘리먼트</param>
/// <param name="elementID">엘리먼트 ID</param>
/// <returns>처리 결과</returns>
public static bool InvokeElementByID(AutomationElement windowElement, string elementID)
{
return InvokeElement
(
windowElement,
new PropertyCondition(AutomationElement.AutomationIdProperty, elementID)
);
}
#endregion
#region 엘리먼트 확장하기 - ExpandElement(element)
/// <summary>
/// 엘리먼트 확장하기
/// </summary>
/// <param name="element">엘리먼트</param>
/// <returns>처리 결과</returns>
public static bool ExpandElement(AutomationElement element)
{
if(element == null)
{
return false;
}
ExpandCollapsePattern pattern = element.GetCurrentPattern(ExpandCollapsePattern.Pattern) as ExpandCollapsePattern;
pattern.Expand();
return true;
}
#endregion
#region 엘리먼트 확장하기 - ExpandElement(windowElement, condition)
/// <summary>
/// 엘리먼트 확장하기
/// </summary>
/// <param name="windowElement">윈도우 엘리먼트</param>
/// <param name="condition">조건</param>
/// <returns>처리 결과</returns>
private static bool ExpandElement(AutomationElement windowElement, Condition condition)
{
AutomationElement element = GetElement(windowElement, condition);
return ExpandElement(element);
}
#endregion
#region 명칭으로 엘리먼트 확장하기 - ExpandElementByName(windowElement, elementName)
/// <summary>
/// 명칭으로 엘리먼트 확장하기
/// </summary>
/// <param name="windowElement">윈도우 엘리먼트</param>
/// <param name="elementName">엘리먼트명</param>
/// <returns>처리 결과</returns>
public static bool ExpandElementByName(AutomationElement windowElement, string elementName)
{
return ExpandElement
(
windowElement,
new PropertyCondition(AutomationElement.NameProperty, elementName)
);
}
#endregion
#region ID로 엘리먼트 확장하기 - ExpandElementByID(windowElement, elementID)
/// <summary>
/// ID로 엘리먼트 확장하기
/// </summary>
/// <param name="windowElement">윈도우 엘리먼트</param>
/// <param name="elementID">엘리먼트 ID</param>
/// <returns>처리 결과</returns>
public static bool ExpandElementByID(AutomationElement windowElement, string elementID)
{
return ExpandElement
(
windowElement,
new PropertyCondition(AutomationElement.AutomationIdProperty, elementID)
);
}
#endregion
#region ID로 엘리먼트 토글하기 - ToggleElementByID(windowElement, elementID)
/// <summary>
/// ID로 엘리먼트 토글하기
/// </summary>
/// <param name="windowElement">윈도우 엘리먼트</param>
/// <param name="elementID">엘리먼트 ID</param>
public static void ToggleElementByID(AutomationElement windowElement, string elementID)
{
AutomationElement element = GetElement(windowElement, new PropertyCondition(AutomationElement.AutomationIdProperty, elementID));
TogglePattern pattern = element.GetCurrentPattern(TogglePattern.Pattern) as TogglePattern;
pattern.Toggle();
}
#endregion
#region 항목 선택하기 - SelectItem(windowElement, elementID, itemIndex)
/// <summary>
/// 항목 선택하기
/// </summary>
/// <param name="windowElement">윈도우 엘리먼트</param>
/// <param name="elementID">엘리먼트 ID</param>
/// <param name="itemIndex">항목 인덱스</param>
public static void SelectItem(AutomationElement windowElement, string elementID, int itemIndex)
{
AutomationElement element = GetElementByID(windowElement, elementID);
AutomationElementCollection itemCollection = element.FindAll
(
TreeScope.Children,
new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.ListItem)
);
ExpandCollapsePattern pattern = (ExpandCollapsePattern)element.GetCurrentPattern(ExpandCollapsePattern.Pattern);
pattern.Expand();
AutomationElement itemElement = itemCollection[itemIndex];
object selectPattern = null;
if(itemElement.TryGetCurrentPattern(SelectionItemPattern.Pattern, out selectPattern))
{
((SelectionItemPattern)selectPattern).Select();
}
}
#endregion
#region 선택 여부 구하기 - IsSelected(windowElement, elementID)
/// <summary>
/// 선택 여부 구하기
/// </summary>
/// <param name="windowElement">윈도우 엘리먼트</param>
/// <param name="elementID">엘리먼트 ID</param>
/// <returns>선택 여부</returns>
public static bool IsSelected(AutomationElement windowElement, string elementID)
{
AutomationElement element = GetElementByID(windowElement, elementID);
SelectionItemPattern pattern = element.GetCurrentPattern(SelectionItemPattern.Pattern) as SelectionItemPattern;
return pattern.Current.IsSelected;
}
#endregion
#region 이용 가능 여부 구하기 - IsEnabled(windowElement, elementID)
/// <summary>
/// 이용 가능 여부 구하기
/// </summary>
/// <param name="windowElement">윈도우 엘리먼트</param>
/// <param name="elementID">엘리먼트 ID</param>
/// <returns>이용 가능 여부</returns>
public static bool IsEnabled(AutomationElement windowElement, string elementID)
{
AutomationElement element = GetElementByID(windowElement, elementID);
return (bool)element.GetCurrentPropertyValue(AutomationElement.IsEnabledProperty);
}
#endregion
#region 엘리먼트 선택하기 - SelectElement(element)
/// <summary>
/// 엘리먼트 선택하기
/// </summary>
/// <param name="element">엘리먼트</param>
public static void SelectElement(AutomationElement element)
{
SelectionItemPattern pattern = element.GetCurrentPattern(SelectionItemPattern.Pattern) as SelectionItemPattern;
pattern.Select();
}
#endregion
#region 엘리먼트 선택하기 - SelectElement(windowElement, elementID)
/// <summary>
/// 엘리먼트 선택하기
/// </summary>
/// <param name="windowElement">윈도우 엘리먼트</param>
/// <param name="elementID">엘리먼트 ID</param>
public static void SelectElement(AutomationElement windowElement, string elementID)
{
AutomationElement element = GetElementByID(windowElement, elementID);
SelectionItemPattern pattern = element.GetCurrentPattern(SelectionItemPattern.Pattern) as SelectionItemPattern;
pattern.Select();
}
#endregion
#region 값 설정하기 - SetValue(windowElement, elementID, value)
/// <summary>
/// 값 설정하기
/// </summary>
/// <param name="windowElement">윈도우 엘리먼트</param>
/// <param name="elementID">엘리먼트 ID</param>
/// <param name="value">값</param>
public static void SetValue(AutomationElement windowElement, string elementID, string value)
{
AutomationElement element = GetElementByID(windowElement, elementID);
ValuePattern pattern = element.GetCurrentPattern(ValuePattern.Pattern) as ValuePattern;
pattern.SetValue(value);
}
#endregion
#region 자식 카운트 구하기 - GetChildCount(windowElement, elementID)
/// <summary>
/// 자식 카운트 구하기
/// </summary>
/// <param name="windowElement">윈도우 엘리먼트</param>
/// <param name="elementID">엘리먼트 ID</param>
/// <returns>자식 카운트</returns>
public static int GetChildCount(AutomationElement windowElement, string elementID)
{
AutomationElement element = GetElementByID(windowElement, elementID);
return element.FindAll(TreeScope.Children, PropertyCondition.TrueCondition).Count;
}
#endregion
#region 엘리먼트 텍스트 구하기 - GetElementText(element)
/// <summary>
/// 엘리먼트 텍스트 구하기
/// </summary>
/// <param name="element">엘리먼트</param>
/// <returns>엘리먼트 텍스트</returns>
public static string GetElementText(AutomationElement element)
{
TextPattern pattern = (TextPattern)element.GetCurrentPattern(TextPattern.Pattern);
return pattern.DocumentRange.GetText(-1);
}
#endregion
#region 엘리먼트 텍스트 구하기 - GetElementText(windowElement, elementID)
/// <summary>
/// 엘리먼트 텍스트 구하기
/// </summary>
/// <param name="windowElement">윈도우 엘리먼트</param>
/// <param name="elementID">엘리먼트 ID</param>
/// <returns>엘리먼트 텍스트</returns>
public static string GetElementText(AutomationElement windowElement, string elementID)
{
TextPattern pattern = (TextPattern)GetElementByID(windowElement, elementID).GetCurrentPattern(TextPattern.Pattern);
return pattern.DocumentRange.GetText(-1);
}
#endregion
#region 엘리먼트 호출하기 - InvokeElement(element)
/// <summary>
/// 엘리먼트 호출하기
/// </summary>
/// <param name="element">엘리먼트</param>
public static void InvokeElement(AutomationElement element)
{
InvokePattern pattern = (InvokePattern)element.GetCurrentPattern(InvokePattern.Pattern);
pattern.Invoke();
Thread.Sleep(500);
}
#endregion
#region 첫번째 자식 구하기 - GetFirstChild(windowElement)
/// <summary>
/// 첫번째 자식 구하기
/// </summary>
/// <param name="windowElement">윈도우 엘리먼트</param>
/// <returns>첫번째 자식</returns>
public static AutomationElement GetFirstChild(AutomationElement windowElement)
{
return GetElement(windowElement, Condition.TrueCondition);
}
#endregion
#region 첫번째 자식 구하기 - GetFirstChild(parentElement, childName)
/// <summary>
/// 첫번째 자식 구하기
/// </summary>
/// <param name="parentElement">부모 엘리먼트</param>
/// <param name="childName">자식 명칭</param>
/// <returns>첫번째 자식</returns>
public static AutomationElement GetFirstChild(AutomationElement parentElement, string childName)
{
return GetElement(parentElement, new PropertyCondition(AutomationElement.NameProperty, childName));
}
#endregion
#region 테이블 셀 엘리먼트 호출하기 - InvokeTableCellElement(windowElement, elementID, row, column)
/// <summary>
/// 테이블 셀 엘리먼트 호출하기
/// </summary>
/// <param name="windowElement">윈도우 엘리먼트</param>
/// <param name="elementID">엘리먼트 ID</param>
/// <param name="row">행</param>
/// <param name="column">컬럼</param>
public static void InvokeTableCellElement(AutomationElement windowElement, string elementID, int row, int column)
{
AutomationElement tableElement = GetElementByID(windowElement, elementID);
GridPattern pattern = tableElement.GetCurrentPattern(GridPattern.Pattern) as GridPattern;
AutomationElement cellElement = pattern.GetItem(row, column);
AutomationElement hyperLinkElement = GetFirstChild(cellElement);
InvokeElement(hyperLinkElement);
}
#endregion
#region 선택 엘리먼트 구하기 - GetSelectedElement(parentElement)
/// <summary>
/// 선택 엘리먼트 구하기
/// </summary>
/// <param name="parentElement">부모 엘리먼트</param>
/// <returns>선택 엘리먼트</returns>
public static AutomationElement GetSelectedElement(AutomationElement parentElement)
{
return GetElement(parentElement, new PropertyCondition(SelectionItemPattern.IsSelectedProperty, true));
}
#endregion
#region 리스트 뷰에서 데이터 테이블 구하기 - GetDataTableFromListView(windowElement, elementID)
/// <summary>
/// 리스트 뷰에서 데이터 테이블 구하기
/// </summary>
/// <param name="windowElement">윈도우 엘리먼트</param>
/// <param name="elementID">엘리먼트 ID</param>
/// <returns>데이터 테이블</returns>
public static DataTable GetDataTableFromListView(AutomationElement windowElement, string elementID)
{
AutomationElement element = GetElementByID(windowElement, elementID);
GridPattern pattern = element.GetCurrentPattern(GridPattern.Pattern) as GridPattern;
DataTable dataTable = new DataTable();
for(int i = 0; i < pattern.Current.ColumnCount; i++)
{
dataTable.Columns.Add(GetColumnHeaderID(pattern.GetItem(0, i)));
}
for(int i = 0; i < pattern.Current.RowCount; i++)
{
dataTable.Rows.Add();
for(int j = 0; j < pattern.Current.ColumnCount; j++)
{
AutomationElement cellElement = pattern.GetItem(i, j);
string columnName = GetColumnHeaderID(cellElement);
dataTable.Rows[i][columnName] = cellElement.GetCurrentPropertyValue(AutomationElement.NameProperty);
}
}
return dataTable;
}
#endregion
#region 선택에 엘리먼트 추가하기 - AddElementToSelection(element)
/// <summary>
/// 선택에 엘리먼트 추가하기
/// </summary>
/// <param name="element">엘리먼트</param>
public static void AddElementToSelection(AutomationElement element)
{
SelectionItemPattern pattern = element.GetCurrentPattern(SelectionItemPattern.Pattern) as SelectionItemPattern;
pattern.AddToSelection();
}
#endregion
#region 마우스 클릭 실행하기 - PerformMouseClick(windowElement, elementID)
/// <summary>
/// 마우스 클릭 실행하기
/// </summary>
/// <param name="windowElement">윈도우 엘리먼트</param>
/// <param name="elementID">엘리먼트 ID</param>
public static void PerformMouseClick(AutomationElement windowElement, string elementID)
{
try
{
AutomationElement element = GetElementByID(windowElement, elementID);
MouseHelper.ClickMouseLeftButton(GetPointToClick(element));
}
catch(NoClickablePointException)
{
AutomationElement element = GetElementByID(windowElement, elementID);
int x = (int)element.GetClickablePoint().X;
int y = (int)element.GetClickablePoint().Y;
Point point = new Point(x, y);
MouseHelper.ClickMouseLeftButton(point);
}
}
#endregion
#region 마우스 오른쪽 버튼 클릭 실행하기 - PerformMouseRightButtonClick(windowElement, elementID)
/// <summary>
/// 마우스 오른쪽 버튼 클릭 실행하기
/// </summary>
/// <param name="windowElement">윈도우 엘리먼트</param>
/// <param name="elementID">엘리먼트 ID</param>
public static void PerformMouseRightButtonClick(AutomationElement windowElement, string elementID)
{
AutomationElement element = null;
try
{
element = GetElementByID(windowElement, elementID);
MouseHelper.ClickMouseRightButton(GetPointToClick(element));
}
catch(NoClickablePointException)
{
element = GetElementByID(windowElement, elementID);
MouseHelper.ClickMouseRightButton(GetPointToClick(element));
}
}
#endregion
#region 존재 여부 구하기 - Exists(windowElement, elementID)
/// <summary>
/// 존재 여부 구하기
/// </summary>
/// <param name="windowElement">윈도우 엘리먼트</param>
/// <param name="elementID">엘리먼트 ID</param>
/// <returns>존재 여부</returns>
public static bool Exists(AutomationElement windowElement, string elementID)
{
try
{
AutomationElement element = GetElement(windowElement, new PropertyCondition(AutomationElement.AutomationIdProperty, elementID));
return element != null;
}
catch
{
return false;
}
}
#endregion
#region 미존재 여부 구하기 - NotExists(windowElement, elementName)
/// <summary>
/// 미존재 여부 구하기
/// </summary>
/// <param name="windowElement">윈도우 엘리먼트</param>
/// <param name="elementName">엘리먼트명</param>
/// <returns>미존재 여부</returns>
public static bool NotExists(AutomationElement windowElement, string elementName)
{
try
{
AutomationElement element = windowElement.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.NameProperty, elementName));
return element == null;
}
catch
{
return false;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////// Private
#region WinForm 포인트 구하기 - GetWinFormPoint(wpfPoint)
/// <summary>
/// WinForm 포인트 구하기
/// </summary>
/// <param name="wpfPoint">WPF 포인트</param>
/// <returns>WinForm 포인트</returns>
private static System.Drawing.Point GetWinFormPoint(System.Windows.Point wpfPoint)
{
return new System.Drawing.Point
{
X = Convert.ToInt32(wpfPoint.X),
Y = Convert.ToInt32(wpfPoint.Y)
};
}
#endregion
#region 엘리먼트 컬렉션 구하기 - GetElementCollection(windowElement, condition)
/// <summary>
/// 엘리먼트 컬렉션 구하기
/// </summary>
/// <param name="windowElement">윈도우 엘리먼트</param>
/// <param name="condition">조건</param>
/// <returns>자동화 엘리먼트 컬렉션</returns>
private static AutomationElementCollection GetElementCollection(AutomationElement windowElement, Condition condition)
{
return windowElement.FindAll(TreeScope.Descendants, condition);
}
#endregion
#region 엘리먼트 구하기 - GetElement(windowElement, condition)
/// <summary>
/// 엘리먼트 구하기
/// </summary>
/// <param name="windowElement">윈도우 엘리먼트</param>
/// <param name="condition">조건</param>
/// <returns>자동화 엘리먼트</returns>
private static AutomationElement GetElement(AutomationElement windowElement, Condition condition)
{
DateTime startTime = DateTime.Now;
AutomationElement element = null;
do
{
element = windowElement.FindFirst(TreeScope.Descendants, condition);
if(element == null)
{
Thread.Sleep(500);
}
if((DateTime.Now - startTime).TotalSeconds > ELEMENT_SEARCH_TIMEOUT_SECOND_COUNT)
{
throw new TimeoutException
(
$"Searching for an element took longer than specified timeout of {ELEMENT_SEARCH_TIMEOUT_SECOND_COUNT} seconds"
);
}
}
while(element == null);
return element;
}
#endregion
#region 컬럼 헤더 ID 구하기 - GetColumnHeaderID(cellElement)
/// <summary>
/// 컬럼 헤더 ID 구하기
/// </summary>
/// <param name="cellElement">셀 엘리먼트</param>
/// <returns>컬럼 헤더 ID</returns>
private static string GetColumnHeaderID(AutomationElement cellElement)
{
AutomationElement gridElement = cellElement.GetCurrentPropertyValue(GridItemPatternIdentifiers.ContainingGridProperty) as AutomationElement;
TablePattern pattern = gridElement.GetCurrentPattern(TablePattern.Pattern) as TablePattern;
int column = (int)cellElement.GetCurrentPropertyValue(GridItemPatternIdentifiers.ColumnProperty);
AutomationElement headerElement = pattern.Current.GetColumnHeaders()[column];
return (string)headerElement.GetCurrentPropertyValue(AutomationElement.NameProperty);
}
#endregion
#region 클릭 포인트 구하기 - GetPointToClick(element)
/// <summary>
/// 클릭 포인트 구하기
/// </summary>
/// <param name="element">엘리먼트</param>
/// <returns>WinForm 포인트</returns>
private static System.Drawing.Point GetPointToClick(AutomationElement element)
{
return GetWinFormPoint
(
new System.Windows.Point
(
element.Current.BoundingRectangle.Left + 10,
element.Current.BoundingRectangle.Top + 10
)
);
}
#endregion
}
}