c# - 使用 UI 自动化订阅 ComboBox 选择更改事件
问题描述
我是 UI 自动化的新手。
有一个 ComboBox 类型的 AutomationElement。
我正在寻找一种方法来订阅 ComboBox 更改其Name
属性时引发的事件。
这是我正在尝试做的,但它不起作用:
Automation.AddAutomationPropertyChangedEventHandler(
elementComboBox,
TreeScope.Element,
new AutomationPropertyChangedEventHandler(OnUIAutomationPropChanged),
NameProperty
);
解决方案
It appears you already know how to get to the ComboBox element, so let's just setup an AddAutomationPropertyChangedEventHandler to detect ExpandCollapsePattern.ExpandCollapseStateProperty change events.
The ComboBox controls are composited objects composed of:
- The external container,
- The internal Edit Control, used to enter a selection/search a value, available when the ComboBox is of type DropDown
- The internal ListControl, used to present the list of items contained in the ComboBox, shown as a the ComboBox drop down element.
The item selection belongs to the ListControl, it's this control we need to get the value from.
The List Automation Element supports the SelectionPattern.
The SelectionPatter.GetSelection() method return a collection of ListItem
elements: the Name
property of the Item returns the current selection value.
With the AutomationElement identifying the ComboBox of interest, when can setup an event handler for its ExpandCollapseState
property changes like this:
bool success = SetExpandCollapseEventHandler(elementComboBox);
// [...]
// Remove the handler when you're done with it
RemoveExpandCollapseEventHandler(elementComboBox);
Here, string selectedValue
contains the value selected when the ComboBox is closed:
Of course, you could read the value both when the ExpandCollapseState is Expanded
and Collpsed
, to compare the current value and the selected one
private AutomationPropertyChangedEventHandler ExpandCollapsedHandler = null;
public bool SetExpandCollapseEventHandler(AutomationElement element)
{
if ((bool)element.GetCurrentPropertyValue(AutomationElement.IsExpandCollapsePatternAvailableProperty)) {
Automation.AddAutomationPropertyChangedEventHandler(element, TreeScope.Element,
ExpandCollapsedHandler = new AutomationPropertyChangedEventHandler(OnExpandCollapeChanged),
ExpandCollapsePattern.ExpandCollapseStateProperty);
return true;
}
return false;
}
private void OnExpandCollapeChanged(object elm, AutomationPropertyChangedEventArgs e)
{
var element = elm as AutomationElement;
if (element.TryGetCurrentPattern(ExpandCollapsePattern.Pattern, out object value)) {
var state = (value as ExpandCollapsePattern).Current.ExpandCollapseState;
if (state == ExpandCollapseState.Collapsed) {
var listElement = element.FindFirst(TreeScope.Children,
new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.List));
if (listElement != null) {
var selectedItem = (listElement.GetCurrentPattern(
SelectionPattern.Pattern) as SelectionPattern).Current.GetSelection().FirstOrDefault();
string selectedValue = selectedItem?.Current.Name;
}
}
}
}
void RemoveExpandCollapseEventHandler(AutomationElement element)
{
Automation.RemoveAutomationPropertyChangedEventHandler(element, ExpandCollapsedHandler);
ExpandCollapsedHandler = null;
}
► Subscribe to SelectionItemPattern's ElementSelectedEvent:
If you need to know when any elements of the ComboBox List is changed/selected when no actual User selection is made using the GUI, you can subscribe to the events raised by the child elements of the List
element.
You need just one handler, attached to a wider scope: TreeScope.Children
.
WARNING: Since these events need to be handled asynchnonously, the events are raised in Threadpool threads.
This has consequences:
- you cannot access controls in the UI thread directly (you need to
BeginInvoke()
) - You MUST remove the
AutomationEventHandler
if/when the ComboBox Control is disposed (e.g., when the parent Window is closed), otherwise your app will become unstable and probably stuck eternally waiting for an event to return a value from a Element that, at a certain point, doesn't answer anymore.
You may want to use a WindowPattern.WindowClosedEvent handler to receive notifications when the parent Window is closed, then call the Automation.RemoveAutomationEventHandler
(as shown here), but probably (to evaluate based on the context of the operations) also the Automation.RemoveAllEventHandlers() method.
Called as:
bool success = SetListItemChangedEventHandler(elementComboBox);
// [...]
// Remove the handler when you're done with it
RemoveListItemChangedHandler();
private AutomationElement listElement = null;
private AutomationEventHandler ListItemChangedHandler = null;
public bool SetListItemChangedEventHandler(AutomationElement combobox)
{
listElement = combobox.FindFirst(TreeScope.Children,
new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.List));
if ((bool)listElement.GetCurrentPropertyValue(AutomationElement.IsSelectionPatternAvailableProperty)) {
Automation.AddAutomationEventHandler(SelectionItemPattern.ElementSelectedEvent,
listElement, TreeScope.Children,
ListItemChangedHandler = new AutomationEventHandler(OnListItemChanged));
return true;
}
return false;
}
private void OnListItemChanged(object elm, AutomationEventArgs e)
{
string selectedValue = (elm as AutomationElement)?.Current.Name;
}
private void RemoveListItemChangedHandler()
{
Automation.RemoveAutomationEventHandler(
SelectionItemPattern.ElementSelectedEvent, listElement, ListItemChangedHandler);
ListItemChangedHandler = null;
}
推荐阅读
- python - 无法在 Docker 映像中导入本地 Python 模块
- python - 如何通过在另一列上迭代创建一列?
- ruby-on-rails - 在出现 FIFO 权限错误的 AWS Red Hat EL 7 上生成乘客/铁路应用程序时出现问题
- java - 将 Base64 字符串保存到文件
- excel - 需要根据 3 个标准返回值
- javascript - 如何使用js/jquery访问标签的title属性
- python - 查询数据框和过滤列值并返回计数
- ansible - 我怎样才能用'y'在ansible中用expect回答一些问题?
- javascript - State not showing in my text component React Native
- c# - How to subtract a property value from a list on a condition