← All pillars
Addressing an element

Locators

One grammar, written once, read the same way by every verb — and refused at parse time rather than answered with a null at run time.

THE WINDOW THE CONTROL VIEW App — Relatórios Pane Pane (framework wrapper) Save StatusBar Window#main Pane#reportHost Pane <- the wrapper nobody wrote Button#save StatusBar Window#main > Pane > Button#save — matches, because > is a descendant of, at any depth. A direct-child locator is the one that breaks on somebody else's machine.

What a locator can say

  • The automation id, the control type, or both.
  • The name, the window class, or a pattern the control must carry.
  • An order and an index — the leftmost of the ones that match, the second from the top.
  • A descendant chain, where each step is a descendant of the last at any depth.

Why the combinator is not a direct child

UI Automation wraps controls in panes that differ between frameworks, between versions of one framework, and between a maximised window and a restored one. A direct-child locator is therefore the one that passes here and breaks on somebody else's machine — which is the worst failure mode available to a locator, because it looks like flakiness rather than like a decision.

Refusals, not first matches

  • A locator that does not parse names the position and the reason.
  • Locator.TryParse answers without throwing, for a caller collecting refusals rather than stopping at the first.
  • Two elements matching one step is a refusal — a quiet first-match is a test that passes against the wrong control until the order changes.
  • A misspelt control type or pattern is answered with the nearest name UI Automation actually has, because the vocabulary is read from UI Automation rather than from a list kept here by hand.

And the tree is readable

The control view under a window or an element comes back as a tree, or as lines a person reads. Which is the difference between “it did not find it” and a question with an answer.