InputElement.cs 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059
  1. #nullable enable
  2. using System;
  3. using System.Collections.Generic;
  4. using Avalonia.Controls;
  5. using Avalonia.Controls.Metadata;
  6. using Avalonia.Input.GestureRecognizers;
  7. using Avalonia.Input.TextInput;
  8. using Avalonia.Interactivity;
  9. using Avalonia.Reactive;
  10. using Avalonia.VisualTree;
  11. namespace Avalonia.Input
  12. {
  13. /// <summary>
  14. /// Implements input-related functionality for a control.
  15. /// </summary>
  16. [PseudoClasses(":disabled", ":focus", ":focus-visible", ":focus-within", ":pointerover")]
  17. public class InputElement : Interactive, IInputElement
  18. {
  19. /// <summary>
  20. /// Defines the <see cref="Focusable"/> property.
  21. /// </summary>
  22. public static readonly StyledProperty<bool> FocusableProperty =
  23. AvaloniaProperty.Register<InputElement, bool>(nameof(Focusable));
  24. /// <summary>
  25. /// Defines the <see cref="IsEnabled"/> property.
  26. /// </summary>
  27. public static readonly StyledProperty<bool> IsEnabledProperty =
  28. AvaloniaProperty.Register<InputElement, bool>(nameof(IsEnabled), true);
  29. /// <summary>
  30. /// Defines the <see cref="IsEffectivelyEnabled"/> property.
  31. /// </summary>
  32. public static readonly DirectProperty<InputElement, bool> IsEffectivelyEnabledProperty =
  33. AvaloniaProperty.RegisterDirect<InputElement, bool>(
  34. nameof(IsEffectivelyEnabled),
  35. o => o.IsEffectivelyEnabled);
  36. /// <summary>
  37. /// Gets or sets associated mouse cursor.
  38. /// </summary>
  39. public static readonly StyledProperty<Cursor?> CursorProperty =
  40. AvaloniaProperty.Register<InputElement, Cursor?>(nameof(Cursor), null, true);
  41. /// <summary>
  42. /// Defines the <see cref="IsKeyboardFocusWithin"/> property.
  43. /// </summary>
  44. public static readonly DirectProperty<InputElement, bool> IsKeyboardFocusWithinProperty =
  45. AvaloniaProperty.RegisterDirect<InputElement, bool>(
  46. nameof(IsKeyboardFocusWithin),
  47. o => o.IsKeyboardFocusWithin);
  48. /// <summary>
  49. /// Defines the <see cref="IsFocused"/> property.
  50. /// </summary>
  51. public static readonly DirectProperty<InputElement, bool> IsFocusedProperty =
  52. AvaloniaProperty.RegisterDirect<InputElement, bool>(nameof(IsFocused), o => o.IsFocused);
  53. /// <summary>
  54. /// Defines the <see cref="IsHitTestVisible"/> property.
  55. /// </summary>
  56. public static readonly StyledProperty<bool> IsHitTestVisibleProperty =
  57. AvaloniaProperty.Register<InputElement, bool>(nameof(IsHitTestVisible), true);
  58. /// <summary>
  59. /// Defines the <see cref="IsPointerOver"/> property.
  60. /// </summary>
  61. public static readonly DirectProperty<InputElement, bool> IsPointerOverProperty =
  62. AvaloniaProperty.RegisterDirect<InputElement, bool>(nameof(IsPointerOver), o => o.IsPointerOver);
  63. /// <summary>
  64. /// Defines the <see cref="IsTabStop"/> property.
  65. /// </summary>
  66. public static readonly StyledProperty<bool> IsTabStopProperty =
  67. KeyboardNavigation.IsTabStopProperty.AddOwner<InputElement>();
  68. /// <summary>
  69. /// Defines the <see cref="GotFocus"/> event.
  70. /// </summary>
  71. public static readonly RoutedEvent<GotFocusEventArgs> GotFocusEvent =
  72. RoutedEvent.Register<InputElement, GotFocusEventArgs>(nameof(GotFocus), RoutingStrategies.Bubble);
  73. /// <summary>
  74. /// Defines the <see cref="GettingFocus"/> event.
  75. /// </summary>
  76. public static readonly RoutedEvent<FocusChangingEventArgs> GettingFocusEvent =
  77. RoutedEvent.Register<InputElement, FocusChangingEventArgs>(nameof(GettingFocus), RoutingStrategies.Bubble);
  78. /// <summary>
  79. /// Defines the <see cref="LostFocus"/> event.
  80. /// </summary>
  81. public static readonly RoutedEvent<RoutedEventArgs> LostFocusEvent =
  82. RoutedEvent.Register<InputElement, RoutedEventArgs>(nameof(LostFocus), RoutingStrategies.Bubble);
  83. /// <summary>
  84. /// Defines the <see cref="LosingFocus"/> event.
  85. /// </summary>
  86. public static readonly RoutedEvent<FocusChangingEventArgs> LosingFocusEvent =
  87. RoutedEvent.Register<InputElement, FocusChangingEventArgs>(nameof(LosingFocus), RoutingStrategies.Bubble);
  88. /// <summary>
  89. /// Defines the <see cref="KeyDown"/> event.
  90. /// </summary>
  91. public static readonly RoutedEvent<KeyEventArgs> KeyDownEvent =
  92. RoutedEvent.Register<InputElement, KeyEventArgs>(
  93. nameof(KeyDown),
  94. RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
  95. /// <summary>
  96. /// Defines the <see cref="KeyUp"/> event.
  97. /// </summary>
  98. public static readonly RoutedEvent<KeyEventArgs> KeyUpEvent =
  99. RoutedEvent.Register<InputElement, KeyEventArgs>(
  100. nameof(KeyUp),
  101. RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
  102. /// <summary>
  103. /// Defines the <see cref="TabIndex"/> property.
  104. /// </summary>
  105. public static readonly StyledProperty<int> TabIndexProperty =
  106. KeyboardNavigation.TabIndexProperty.AddOwner<InputElement>();
  107. /// <summary>
  108. /// Defines the <see cref="TextInput"/> event.
  109. /// </summary>
  110. public static readonly RoutedEvent<TextInputEventArgs> TextInputEvent =
  111. RoutedEvent.Register<InputElement, TextInputEventArgs>(
  112. nameof(TextInput),
  113. RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
  114. /// <summary>
  115. /// Defines the <see cref="TextInputMethodClientRequested"/> event.
  116. /// </summary>
  117. public static readonly RoutedEvent<TextInputMethodClientRequestedEventArgs> TextInputMethodClientRequestedEvent =
  118. RoutedEvent.Register<InputElement, TextInputMethodClientRequestedEventArgs>(
  119. nameof(TextInputMethodClientRequested),
  120. RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
  121. /// <summary>
  122. /// Defines the <see cref="PointerEntered"/> event.
  123. /// </summary>
  124. public static readonly RoutedEvent<PointerEventArgs> PointerEnteredEvent =
  125. RoutedEvent.Register<InputElement, PointerEventArgs>(
  126. nameof(PointerEntered),
  127. RoutingStrategies.Direct);
  128. /// <summary>
  129. /// Defines the <see cref="PointerExited"/> event.
  130. /// </summary>
  131. public static readonly RoutedEvent<PointerEventArgs> PointerExitedEvent =
  132. RoutedEvent.Register<InputElement, PointerEventArgs>(
  133. nameof(PointerExited),
  134. RoutingStrategies.Direct);
  135. /// <summary>
  136. /// Defines the <see cref="PointerMoved"/> event.
  137. /// </summary>
  138. public static readonly RoutedEvent<PointerEventArgs> PointerMovedEvent =
  139. RoutedEvent.Register<InputElement, PointerEventArgs>(
  140. nameof(PointerMoved),
  141. RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
  142. /// <summary>
  143. /// Defines the <see cref="PointerPressed"/> event.
  144. /// </summary>
  145. public static readonly RoutedEvent<PointerPressedEventArgs> PointerPressedEvent =
  146. RoutedEvent.Register<InputElement, PointerPressedEventArgs>(
  147. nameof(PointerPressed),
  148. RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
  149. /// <summary>
  150. /// Defines the <see cref="PointerReleased"/> event.
  151. /// </summary>
  152. public static readonly RoutedEvent<PointerReleasedEventArgs> PointerReleasedEvent =
  153. RoutedEvent.Register<InputElement, PointerReleasedEventArgs>(
  154. nameof(PointerReleased),
  155. RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
  156. /// <summary>
  157. /// Defines the <see cref="PointerCaptureLost"/> routed event.
  158. /// </summary>
  159. public static readonly RoutedEvent<PointerCaptureLostEventArgs> PointerCaptureLostEvent =
  160. RoutedEvent.Register<InputElement, PointerCaptureLostEventArgs>(
  161. nameof(PointerCaptureLost),
  162. RoutingStrategies.Direct);
  163. /// <summary>
  164. /// Defines the <see cref="PointerWheelChanged"/> event.
  165. /// </summary>
  166. public static readonly RoutedEvent<PointerWheelEventArgs> PointerWheelChangedEvent =
  167. RoutedEvent.Register<InputElement, PointerWheelEventArgs>(
  168. nameof(PointerWheelChanged),
  169. RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
  170. /// <summary>
  171. /// Defines the <see cref="Tapped"/> event.
  172. /// </summary>
  173. public static readonly RoutedEvent<TappedEventArgs> TappedEvent = Gestures.TappedEvent;
  174. /// <summary>
  175. /// Defines the <see cref="RightTapped"/> event.
  176. /// </summary>
  177. public static readonly RoutedEvent<TappedEventArgs> RightTappedEvent = Gestures.RightTappedEvent;
  178. /// <summary>
  179. /// Defines the <see cref="Holding"/> event.
  180. /// </summary>
  181. public static readonly RoutedEvent<HoldingRoutedEventArgs> HoldingEvent = Gestures.HoldingEvent;
  182. /// <summary>
  183. /// Defines the <see cref="DoubleTapped"/> event.
  184. /// </summary>
  185. public static readonly RoutedEvent<TappedEventArgs> DoubleTappedEvent = Gestures.DoubleTappedEvent;
  186. private bool _isEffectivelyEnabled = true;
  187. private bool _isFocused;
  188. private bool _isKeyboardFocusWithin;
  189. private bool _isFocusVisible;
  190. private bool _isPointerOver;
  191. private GestureRecognizerCollection? _gestureRecognizers;
  192. /// <summary>
  193. /// Initializes static members of the <see cref="InputElement"/> class.
  194. /// </summary>
  195. static InputElement()
  196. {
  197. IsEnabledProperty.Changed.Subscribe(IsEnabledChanged);
  198. GotFocusEvent.AddClassHandler<InputElement>((x, e) => x.OnGotFocusCore(e));
  199. LostFocusEvent.AddClassHandler<InputElement>((x, e) => x.OnLostFocusCore(e));
  200. GettingFocusEvent.AddClassHandler<InputElement>((x, e) => x.OnGettingFocus(e));
  201. LosingFocusEvent.AddClassHandler<InputElement>((x, e) => x.OnLosingFocus(e));
  202. KeyDownEvent.AddClassHandler<InputElement>((x, e) => x.OnKeyDown(e));
  203. KeyUpEvent.AddClassHandler<InputElement>((x, e) => x.OnKeyUp(e));
  204. TextInputEvent.AddClassHandler<InputElement>((x, e) => x.OnTextInput(e));
  205. PointerEnteredEvent.AddClassHandler<InputElement>((x, e) => x.OnPointerEnteredCore(e));
  206. PointerExitedEvent.AddClassHandler<InputElement>((x, e) => x.OnPointerExitedCore(e));
  207. PointerMovedEvent.AddClassHandler<InputElement>((x, e) => x.OnPointerMoved(e));
  208. PointerPressedEvent.AddClassHandler<InputElement>((x, e) => x.OnPointerPressed(e));
  209. PointerReleasedEvent.AddClassHandler<InputElement>((x, e) => x.OnPointerReleased(e));
  210. PointerCaptureLostEvent.AddClassHandler<InputElement>((x, e) => x.OnPointerCaptureLost(e));
  211. PointerWheelChangedEvent.AddClassHandler<InputElement>((x, e) => x.OnPointerWheelChanged(e));
  212. TappedEvent.AddClassHandler<InputElement>((x, e) => x.OnTapped(e));
  213. RightTappedEvent.AddClassHandler<InputElement>((x, e) => x.OnRightTapped(e));
  214. DoubleTappedEvent.AddClassHandler<InputElement>((x, e) => x.OnDoubleTapped(e));
  215. HoldingEvent.AddClassHandler<InputElement>((x, e) => x.OnHolding(e));
  216. // Gesture only handlers
  217. PointerMovedEvent.AddClassHandler<InputElement>((x, e) => x.OnGesturePointerMoved(e), handledEventsToo: true);
  218. PointerPressedEvent.AddClassHandler<InputElement>((x, e) => x.OnGesturePointerPressed(e), handledEventsToo: true);
  219. PointerReleasedEvent.AddClassHandler<InputElement>((x, e) => x.OnGesturePointerReleased(e), handledEventsToo: true);
  220. PointerCaptureLostEvent.AddClassHandler<InputElement>((x, e) => x.OnGesturePointerCaptureLost(e), handledEventsToo: true);
  221. // Access Key Handling
  222. AccessKeyHandler.AccessKeyEvent.AddClassHandler<InputElement>((x, e) => x.OnAccessKey(e));
  223. }
  224. public InputElement()
  225. {
  226. UpdatePseudoClasses(IsFocused, IsPointerOver);
  227. }
  228. /// <summary>
  229. /// Occurs when the control receives focus.
  230. /// </summary>
  231. public event EventHandler<GotFocusEventArgs>? GotFocus
  232. {
  233. add { AddHandler(GotFocusEvent, value); }
  234. remove { RemoveHandler(GotFocusEvent, value); }
  235. }
  236. /// <summary>
  237. /// Occurs before the control receives focus.
  238. /// </summary>
  239. public event EventHandler<FocusChangingEventArgs>? GettingFocus
  240. {
  241. add { AddHandler(GettingFocusEvent, value); }
  242. remove { RemoveHandler(GettingFocusEvent, value); }
  243. }
  244. /// <summary>
  245. /// Occurs when the control loses focus.
  246. /// </summary>
  247. public event EventHandler<RoutedEventArgs>? LostFocus
  248. {
  249. add { AddHandler(LostFocusEvent, value); }
  250. remove { RemoveHandler(LostFocusEvent, value); }
  251. }
  252. /// <summary>
  253. /// Occurs before the control loses focus.
  254. /// </summary>
  255. public event EventHandler<FocusChangingEventArgs>? LosingFocus
  256. {
  257. add { AddHandler(LosingFocusEvent, value); }
  258. remove { RemoveHandler(LosingFocusEvent, value); }
  259. }
  260. /// <summary>
  261. /// Occurs when a key is pressed while the control has focus.
  262. /// </summary>
  263. public event EventHandler<KeyEventArgs>? KeyDown
  264. {
  265. add { AddHandler(KeyDownEvent, value); }
  266. remove { RemoveHandler(KeyDownEvent, value); }
  267. }
  268. /// <summary>
  269. /// Occurs when a key is released while the control has focus.
  270. /// </summary>
  271. public event EventHandler<KeyEventArgs>? KeyUp
  272. {
  273. add { AddHandler(KeyUpEvent, value); }
  274. remove { RemoveHandler(KeyUpEvent, value); }
  275. }
  276. /// <summary>
  277. /// Occurs when a user typed some text while the control has focus.
  278. /// </summary>
  279. public event EventHandler<TextInputEventArgs>? TextInput
  280. {
  281. add { AddHandler(TextInputEvent, value); }
  282. remove { RemoveHandler(TextInputEvent, value); }
  283. }
  284. /// <summary>
  285. /// Occurs when an input element gains input focus and input method is looking for the corresponding client
  286. /// </summary>
  287. public event EventHandler<TextInputMethodClientRequestedEventArgs>? TextInputMethodClientRequested
  288. {
  289. add { AddHandler(TextInputMethodClientRequestedEvent, value); }
  290. remove { RemoveHandler(TextInputMethodClientRequestedEvent, value); }
  291. }
  292. /// <summary>
  293. /// Occurs when the pointer enters the control.
  294. /// </summary>
  295. public event EventHandler<PointerEventArgs>? PointerEntered
  296. {
  297. add { AddHandler(PointerEnteredEvent, value); }
  298. remove { RemoveHandler(PointerEnteredEvent, value); }
  299. }
  300. /// <summary>
  301. /// Occurs when the pointer leaves the control.
  302. /// </summary>
  303. public event EventHandler<PointerEventArgs>? PointerExited
  304. {
  305. add { AddHandler(PointerExitedEvent, value); }
  306. remove { RemoveHandler(PointerExitedEvent, value); }
  307. }
  308. /// <summary>
  309. /// Occurs when the pointer moves over the control.
  310. /// </summary>
  311. public event EventHandler<PointerEventArgs>? PointerMoved
  312. {
  313. add { AddHandler(PointerMovedEvent, value); }
  314. remove { RemoveHandler(PointerMovedEvent, value); }
  315. }
  316. /// <summary>
  317. /// Occurs when the pointer is pressed over the control.
  318. /// </summary>
  319. public event EventHandler<PointerPressedEventArgs>? PointerPressed
  320. {
  321. add { AddHandler(PointerPressedEvent, value); }
  322. remove { RemoveHandler(PointerPressedEvent, value); }
  323. }
  324. /// <summary>
  325. /// Occurs when the pointer is released over the control.
  326. /// </summary>
  327. public event EventHandler<PointerReleasedEventArgs>? PointerReleased
  328. {
  329. add { AddHandler(PointerReleasedEvent, value); }
  330. remove { RemoveHandler(PointerReleasedEvent, value); }
  331. }
  332. /// <summary>
  333. /// Occurs when the control or its child control loses the pointer capture for any reason,
  334. /// event will not be triggered for a parent control if capture was transferred to another child of that parent control
  335. /// </summary>
  336. public event EventHandler<PointerCaptureLostEventArgs>? PointerCaptureLost
  337. {
  338. add => AddHandler(PointerCaptureLostEvent, value);
  339. remove => RemoveHandler(PointerCaptureLostEvent, value);
  340. }
  341. /// <summary>
  342. /// Occurs when the mouse is scrolled over the control.
  343. /// </summary>
  344. public event EventHandler<PointerWheelEventArgs>? PointerWheelChanged
  345. {
  346. add { AddHandler(PointerWheelChangedEvent, value); }
  347. remove { RemoveHandler(PointerWheelChangedEvent, value); }
  348. }
  349. /// <summary>
  350. /// Occurs when a tap gesture occurs on the control.
  351. /// </summary>
  352. public event EventHandler<TappedEventArgs>? Tapped
  353. {
  354. add { AddHandler(TappedEvent, value); }
  355. remove { RemoveHandler(TappedEvent, value); }
  356. }
  357. /// <summary>
  358. /// Occurs when a right tap gesture occurs on the control.
  359. /// </summary>
  360. public event EventHandler<TappedEventArgs>? RightTapped
  361. {
  362. add { AddHandler(RightTappedEvent, value); }
  363. remove { RemoveHandler(RightTappedEvent, value); }
  364. }
  365. /// <summary>
  366. /// Occurs when a hold gesture occurs on the control.
  367. /// </summary>
  368. public event EventHandler<HoldingRoutedEventArgs>? Holding
  369. {
  370. add { AddHandler(HoldingEvent, value); }
  371. remove { RemoveHandler(HoldingEvent, value); }
  372. }
  373. /// <summary>
  374. /// Occurs when a double-tap gesture occurs on the control.
  375. /// </summary>
  376. public event EventHandler<TappedEventArgs>? DoubleTapped
  377. {
  378. add { AddHandler(DoubleTappedEvent, value); }
  379. remove { RemoveHandler(DoubleTappedEvent, value); }
  380. }
  381. /// <summary>
  382. /// Gets or sets a value indicating whether the control can receive focus.
  383. /// </summary>
  384. public bool Focusable
  385. {
  386. get { return GetValue(FocusableProperty); }
  387. set { SetValue(FocusableProperty, value); }
  388. }
  389. /// <summary>
  390. /// Gets or sets a value indicating whether the control is enabled for user interaction.
  391. /// </summary>
  392. public bool IsEnabled
  393. {
  394. get { return GetValue(IsEnabledProperty); }
  395. set { SetValue(IsEnabledProperty, value); }
  396. }
  397. /// <summary>
  398. /// Gets or sets associated mouse cursor.
  399. /// </summary>
  400. public Cursor? Cursor
  401. {
  402. get { return GetValue(CursorProperty); }
  403. set { SetValue(CursorProperty, value); }
  404. }
  405. /// <summary>
  406. /// Gets a value indicating whether keyboard focus is anywhere within the element or its visual tree child elements.
  407. /// </summary>
  408. public bool IsKeyboardFocusWithin
  409. {
  410. get => _isKeyboardFocusWithin;
  411. internal set => SetAndRaise(IsKeyboardFocusWithinProperty, ref _isKeyboardFocusWithin, value);
  412. }
  413. /// <summary>
  414. /// Gets a value indicating whether the control is focused.
  415. /// </summary>
  416. public bool IsFocused
  417. {
  418. get { return _isFocused; }
  419. private set { SetAndRaise(IsFocusedProperty, ref _isFocused, value); }
  420. }
  421. /// <summary>
  422. /// Gets or sets a value indicating whether the control is considered for hit testing.
  423. /// </summary>
  424. public bool IsHitTestVisible
  425. {
  426. get { return GetValue(IsHitTestVisibleProperty); }
  427. set { SetValue(IsHitTestVisibleProperty, value); }
  428. }
  429. /// <summary>
  430. /// Gets a value indicating whether the pointer is currently over the control.
  431. /// </summary>
  432. public bool IsPointerOver
  433. {
  434. get { return _isPointerOver; }
  435. internal set { SetAndRaise(IsPointerOverProperty, ref _isPointerOver, value); }
  436. }
  437. /// <summary>
  438. /// Gets or sets a value that indicates whether the control is included in tab navigation.
  439. /// </summary>
  440. public bool IsTabStop
  441. {
  442. get => GetValue(IsTabStopProperty);
  443. set => SetValue(IsTabStopProperty, value);
  444. }
  445. /// <inheritdoc/>
  446. public bool IsEffectivelyEnabled
  447. {
  448. get => _isEffectivelyEnabled;
  449. private set
  450. {
  451. SetAndRaise(IsEffectivelyEnabledProperty, ref _isEffectivelyEnabled, value);
  452. PseudoClasses.Set(":disabled", !value);
  453. if (!IsEffectivelyEnabled && FocusManager.GetFocusManager(this) is { } focusManager
  454. && Equals(focusManager.GetFocusedElement(), this))
  455. {
  456. focusManager.ClearFocus();
  457. }
  458. }
  459. }
  460. /// <summary>
  461. /// Gets or sets a value that determines the order in which elements receive focus when the
  462. /// user navigates through controls by pressing the Tab key.
  463. /// </summary>
  464. public int TabIndex
  465. {
  466. get => GetValue(TabIndexProperty);
  467. set => SetValue(TabIndexProperty, value);
  468. }
  469. public List<KeyBinding> KeyBindings { get; } = new List<KeyBinding>();
  470. /// <summary>
  471. /// Allows a derived class to override the enabled state of the control.
  472. /// </summary>
  473. /// <remarks>
  474. /// Derived controls may wish to disable the enabled state of the control without overwriting the
  475. /// user-supplied <see cref="IsEnabled"/> setting. This can be done by overriding this property
  476. /// to return the overridden enabled state. If the value returned from <see cref="IsEnabledCore"/>
  477. /// should change, then the derived control should call <see cref="UpdateIsEffectivelyEnabled()"/>.
  478. /// </remarks>
  479. protected virtual bool IsEnabledCore => IsEnabled;
  480. public GestureRecognizerCollection GestureRecognizers
  481. => _gestureRecognizers ?? (_gestureRecognizers = new GestureRecognizerCollection(this));
  482. /// <inheritdoc />
  483. public bool Focus(NavigationMethod method = NavigationMethod.Unspecified, KeyModifiers keyModifiers = KeyModifiers.None)
  484. {
  485. return FocusManager.GetFocusManager(this)?.Focus(this, method, keyModifiers) ?? false;
  486. }
  487. /// <inheritdoc/>
  488. protected override void OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e)
  489. {
  490. base.OnDetachedFromVisualTreeCore(e);
  491. if (IsFocused)
  492. {
  493. FocusManager.GetFocusManager(e.Root as IInputElement)?.ClearFocusOnElementRemoved(this, e.Parent);
  494. }
  495. IsKeyboardFocusWithin = false;
  496. }
  497. /// <summary>
  498. /// This method is used to execute the action on an effective IInputElement when a corresponding access key has been invoked.
  499. /// By default, the Focus() method is invoked with the NavigationMethod.Tab to indicate a visual focus adorner.
  500. /// Overwrite this method if other methods or additional functionality is needed when an item should receive the focus.
  501. /// </summary>
  502. /// <param name="e">AccessKeyEventArgs are passed on to indicate if there are multiple matches or not.</param>
  503. protected virtual void OnAccessKey(RoutedEventArgs e)
  504. {
  505. Focus(NavigationMethod.Tab);
  506. }
  507. /// <inheritdoc/>
  508. protected override void OnAttachedToVisualTreeCore(VisualTreeAttachmentEventArgs e)
  509. {
  510. base.OnAttachedToVisualTreeCore(e);
  511. UpdateIsEffectivelyEnabled();
  512. }
  513. private void OnGotFocusCore(GotFocusEventArgs e)
  514. {
  515. var isFocused = e.Source == this;
  516. _isFocusVisible = isFocused && (e.NavigationMethod == NavigationMethod.Directional || e.NavigationMethod == NavigationMethod.Tab);
  517. IsFocused = isFocused;
  518. OnGotFocus(e);
  519. }
  520. protected virtual void OnGettingFocus(FocusChangingEventArgs e)
  521. {
  522. }
  523. protected virtual void OnLosingFocus(FocusChangingEventArgs e)
  524. {
  525. }
  526. /// <summary>
  527. /// Invoked when an unhandled <see cref="GotFocusEvent"/> reaches an element in its
  528. /// route that is derived from this class. Implement this method to add class handling
  529. /// for this event.
  530. /// </summary>
  531. /// <param name="e">Data about the event.</param>
  532. protected virtual void OnGotFocus(GotFocusEventArgs e)
  533. {
  534. }
  535. private void OnLostFocusCore(RoutedEventArgs e)
  536. {
  537. _isFocusVisible = false;
  538. IsFocused = false;
  539. OnLostFocus(e);
  540. }
  541. /// <summary>
  542. /// Invoked when an unhandled <see cref="LostFocusEvent"/> reaches an element in its
  543. /// route that is derived from this class. Implement this method to add class handling
  544. /// for this event.
  545. /// </summary>
  546. /// <param name="e">Data about the event.</param>
  547. protected virtual void OnLostFocus(RoutedEventArgs e)
  548. {
  549. }
  550. /// <summary>
  551. /// Invoked when an unhandled <see cref="KeyDownEvent"/> reaches an element in its
  552. /// route that is derived from this class. Implement this method to add class handling
  553. /// for this event.
  554. /// </summary>
  555. /// <param name="e">Data about the event.</param>
  556. protected virtual void OnKeyDown(KeyEventArgs e)
  557. {
  558. }
  559. /// <summary>
  560. /// Invoked when an unhandled <see cref="KeyUpEvent"/> reaches an element in its
  561. /// route that is derived from this class. Implement this method to add class handling
  562. /// for this event.
  563. /// </summary>
  564. /// <param name="e">Data about the event.</param>
  565. protected virtual void OnKeyUp(KeyEventArgs e)
  566. {
  567. }
  568. /// <summary>
  569. /// Invoked when an unhandled <see cref="TextInputEvent"/> reaches an element in its
  570. /// route that is derived from this class. Implement this method to add class handling
  571. /// for this event.
  572. /// </summary>
  573. /// <param name="e">Data about the event.</param>
  574. protected virtual void OnTextInput(TextInputEventArgs e)
  575. {
  576. }
  577. /// <summary>
  578. /// Invoked when an unhandled <see cref="PointerEnteredEvent"/> reaches an element in its
  579. /// route that is derived from this class. Implement this method to add class handling
  580. /// for this event.
  581. /// </summary>
  582. /// <param name="e">Data about the event.</param>
  583. protected virtual void OnPointerEntered(PointerEventArgs e)
  584. {
  585. }
  586. /// <summary>
  587. /// Invoked when an unhandled <see cref="PointerExitedEvent"/> reaches an element in its
  588. /// route that is derived from this class. Implement this method to add class handling
  589. /// for this event.
  590. /// </summary>
  591. /// <param name="e">Data about the event.</param>
  592. protected virtual void OnPointerExited(PointerEventArgs e)
  593. {
  594. }
  595. /// <summary>
  596. /// Invoked when an unhandled <see cref="PointerMovedEvent"/> reaches an element in its
  597. /// route that is derived from this class. Implement this method to add class handling
  598. /// for this event.
  599. /// </summary>
  600. /// <param name="e">Data about the event.</param>
  601. protected virtual void OnPointerMoved(PointerEventArgs e)
  602. {
  603. }
  604. /// <summary>
  605. /// Invoked when an unhandled <see cref="PointerPressedEvent"/> reaches an element in its
  606. /// route that is derived from this class. Implement this method to add class handling
  607. /// for this event.
  608. /// </summary>
  609. /// <param name="e">Data about the event.</param>
  610. protected virtual void OnPointerPressed(PointerPressedEventArgs e)
  611. {
  612. }
  613. /// <summary>
  614. /// Invoked when an unhandled <see cref="PointerReleasedEvent"/> reaches an element in its
  615. /// route that is derived from this class. Implement this method to add class handling
  616. /// for this event.
  617. /// </summary>
  618. /// <param name="e">Data about the event.</param>
  619. protected virtual void OnPointerReleased(PointerReleasedEventArgs e)
  620. {
  621. }
  622. private void OnGesturePointerReleased(PointerReleasedEventArgs e)
  623. {
  624. if (!e.IsGestureRecognitionSkipped)
  625. if (_gestureRecognizers?.HandlePointerReleased(e) == true)
  626. {
  627. e.Handled = true;
  628. }
  629. }
  630. private void OnGesturePointerCaptureLost(PointerCaptureLostEventArgs e)
  631. {
  632. _gestureRecognizers?.HandleCaptureLost(e.Pointer);
  633. }
  634. private void OnGesturePointerPressed(PointerPressedEventArgs e)
  635. {
  636. if (!e.IsGestureRecognitionSkipped)
  637. if (_gestureRecognizers?.HandlePointerPressed(e) == true)
  638. {
  639. e.Handled = true;
  640. }
  641. }
  642. private void OnGesturePointerMoved(PointerEventArgs e)
  643. {
  644. if (!e.IsGestureRecognitionSkipped)
  645. if (_gestureRecognizers?.HandlePointerMoved(e) == true)
  646. {
  647. e.Handled = true;
  648. }
  649. }
  650. /// <summary>
  651. /// Called when FocusManager get the next TabStop to interact with the focused control.
  652. /// </summary>
  653. /// <returns>Next tab stop.</returns>
  654. protected internal virtual InputElement? GetNextTabStopOverride() => null;
  655. /// <summary>
  656. /// Called when FocusManager get the previous TabStop to interact with the focused control.
  657. /// </summary>
  658. /// <returns>Previous tab stop.</returns>
  659. protected internal virtual InputElement? GetPreviousTabStopOverride() => null;
  660. /// <summary>
  661. /// Called when FocusManager is looking for the first focusable element from the specified search scope.
  662. /// </summary>
  663. /// <returns>First focusable element if available.</returns>
  664. protected internal virtual InputElement? GetFirstFocusableElementOverride() => null;
  665. /// <summary>
  666. /// Called when FocusManager is looking for the last focusable element from the specified search scope.
  667. /// </summary>
  668. /// <returns>Last focusable element if available/>.</returns>
  669. protected internal virtual InputElement? GetLastFocusableElementOverride() => null;
  670. /// <summary>
  671. /// Invoked when an unhandled <see cref="PointerCaptureLostEvent"/> reaches an element in its
  672. /// route that is derived from this class. Implement this method to add class handling
  673. /// for this event.
  674. /// </summary>
  675. /// <param name="e">Data about the event.</param>
  676. protected virtual void OnPointerCaptureLost(PointerCaptureLostEventArgs e)
  677. {
  678. }
  679. internal static bool ProcessTabStop(IInputElement? contentRoot,
  680. IInputElement? focusedElement,
  681. IInputElement? candidateTabStopElement,
  682. bool isReverse,
  683. bool didCycleFocusAtRootVisual,
  684. out IInputElement? newTabStop)
  685. {
  686. newTabStop = null;
  687. bool isTabStopOverridden = false;
  688. bool isCandidateTabStopOverridden = false;
  689. IInputElement? currentFocusedTarget = focusedElement;
  690. InputElement? focusedTargetAsIE = focusedElement as InputElement;
  691. InputElement? candidateTargetAsIE = candidateTabStopElement as InputElement;
  692. InputElement? newCandidateTargetAsIE = null;
  693. IInputElement? newCandidateTabStop = null;
  694. IInputElement? spNewTabStop = null;
  695. if (focusedTargetAsIE != null)
  696. {
  697. isTabStopOverridden = focusedTargetAsIE.ProcessTabStopInternal(candidateTabStopElement, isReverse, didCycleFocusAtRootVisual, out spNewTabStop);
  698. }
  699. if (!isTabStopOverridden && candidateTargetAsIE != null)
  700. {
  701. isTabStopOverridden = candidateTargetAsIE.ProcessCandidateTabStopInternal(focusedElement, null, isReverse, out spNewTabStop);
  702. }
  703. else if (isTabStopOverridden && newTabStop != null)
  704. {
  705. newCandidateTargetAsIE = spNewTabStop as InputElement;
  706. if (newCandidateTargetAsIE != null)
  707. {
  708. isCandidateTabStopOverridden = newCandidateTargetAsIE.ProcessCandidateTabStopInternal(focusedElement, spNewTabStop, isReverse, out newCandidateTabStop);
  709. }
  710. }
  711. if (isCandidateTabStopOverridden)
  712. {
  713. if (newCandidateTabStop != null)
  714. {
  715. newTabStop = newCandidateTabStop;
  716. }
  717. isTabStopOverridden = true;
  718. }
  719. else if (isTabStopOverridden)
  720. {
  721. if (newTabStop != null)
  722. {
  723. newTabStop = spNewTabStop;
  724. }
  725. isTabStopOverridden = true;
  726. }
  727. return isTabStopOverridden;
  728. }
  729. private bool ProcessTabStopInternal(IInputElement? candidateTabStopElement,
  730. bool isReverse,
  731. bool didCycleFocusAtRootVisual,
  732. out IInputElement? newTabStop)
  733. {
  734. InputElement? current = this;
  735. newTabStop = null;
  736. var candidateTabStopOverridden = false;
  737. while (current != null && !candidateTabStopOverridden)
  738. {
  739. candidateTabStopOverridden = current.ProcessTabStopOverride(this,
  740. candidateTabStopElement,
  741. isReverse,
  742. didCycleFocusAtRootVisual,
  743. ref newTabStop);
  744. current = (current as Visual)?.Parent as InputElement;
  745. }
  746. return candidateTabStopOverridden;
  747. }
  748. private bool ProcessCandidateTabStopInternal(IInputElement? currentTabStop,
  749. IInputElement? overridenCandidateTabStopElement,
  750. bool isReverse,
  751. out IInputElement? newTabStop)
  752. {
  753. InputElement? current = this;
  754. newTabStop = null;
  755. var candidateTabStopOverridden = false;
  756. while (current != null && !candidateTabStopOverridden)
  757. {
  758. candidateTabStopOverridden = current.ProcessCandidateTabStopOverride(currentTabStop,
  759. this,
  760. overridenCandidateTabStopElement,
  761. isReverse,
  762. ref newTabStop);
  763. current = (current as Visual)?.Parent as InputElement;
  764. }
  765. return candidateTabStopOverridden;
  766. }
  767. protected internal virtual bool ProcessTabStopOverride(IInputElement? focusedElement,
  768. IInputElement? candidateTabStopElement,
  769. bool isReverse,
  770. bool didCycleFocusAtRootVisual,
  771. ref IInputElement? newTabStop)
  772. {
  773. return false;
  774. }
  775. protected internal virtual bool ProcessCandidateTabStopOverride(IInputElement? focusedElement,
  776. IInputElement? candidateTabStopElement,
  777. IInputElement? overridenCandidateTabStopElement,
  778. bool isReverse,
  779. ref IInputElement? newTabStop)
  780. {
  781. return false;
  782. }
  783. /// <summary>
  784. /// Invoked when an unhandled <see cref="PointerWheelChangedEvent"/> reaches an element in its
  785. /// route that is derived from this class. Implement this method to add class handling
  786. /// for this event.
  787. /// </summary>
  788. /// <param name="e">Data about the event.</param>
  789. protected virtual void OnPointerWheelChanged(PointerWheelEventArgs e)
  790. {
  791. }
  792. /// <summary>
  793. /// Invoked when an unhandled <see cref="TappedEvent"/> reaches an element in its
  794. /// route that is derived from this class. Implement this method to add class handling
  795. /// for this event.
  796. /// </summary>
  797. /// <param name="e">Data about the event.</param>
  798. protected virtual void OnTapped(TappedEventArgs e)
  799. {
  800. }
  801. /// <summary>
  802. /// Invoked when an unhandled <see cref="RightTappedEvent"/> reaches an element in its
  803. /// route that is derived from this class. Implement this method to add class handling
  804. /// for this event.
  805. /// </summary>
  806. /// <param name="e">Data about the event.</param>
  807. protected virtual void OnRightTapped(TappedEventArgs e)
  808. {
  809. }
  810. /// <summary>
  811. /// Invoked when an unhandled <see cref="DoubleTappedEvent"/> reaches an element in its
  812. /// route that is derived from this class. Implement this method to add class handling
  813. /// for this event.
  814. /// </summary>
  815. /// <param name="e">Data about the event.</param>
  816. protected virtual void OnDoubleTapped(TappedEventArgs e)
  817. {
  818. }
  819. /// <summary>
  820. /// Invoked when an unhandled <see cref="HoldingEvent"/> reaches an element in its
  821. /// route that is derived from this class. Implement this method to add class handling
  822. /// for this event.
  823. /// </summary>
  824. /// <param name="e">Data about the event.</param>
  825. protected virtual void OnHolding(HoldingRoutedEventArgs e)
  826. {
  827. }
  828. protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
  829. {
  830. base.OnPropertyChanged(change);
  831. if (change.Property == IsFocusedProperty)
  832. {
  833. UpdatePseudoClasses(change.GetNewValue<bool>(), null);
  834. }
  835. else if (change.Property == IsPointerOverProperty)
  836. {
  837. UpdatePseudoClasses(null, change.GetNewValue<bool>());
  838. }
  839. else if (change.Property == IsKeyboardFocusWithinProperty)
  840. {
  841. PseudoClasses.Set(":focus-within", change.GetNewValue<bool>());
  842. }
  843. else if (change.Property == IsVisibleProperty)
  844. {
  845. if (!change.GetNewValue<bool>() && IsKeyboardFocusWithin && FocusManager.GetFocusManager(this) is { } focusManager)
  846. {
  847. if (focusManager.GetFocusedElement() is { } focusedElement && VisualParent != null)
  848. {
  849. focusManager.ClearFocusOnElementRemoved(focusedElement, VisualParent);
  850. }
  851. else
  852. {
  853. focusManager.ClearFocus();
  854. }
  855. }
  856. }
  857. }
  858. /// <summary>
  859. /// Updates the <see cref="IsEffectivelyEnabled"/> property value according to the parent
  860. /// control's enabled state and <see cref="IsEnabledCore"/>.
  861. /// </summary>
  862. protected void UpdateIsEffectivelyEnabled()
  863. {
  864. UpdateIsEffectivelyEnabled(this.GetVisualParent<InputElement>());
  865. }
  866. private static void IsEnabledChanged(AvaloniaPropertyChangedEventArgs e)
  867. {
  868. ((InputElement)e.Sender).UpdateIsEffectivelyEnabled();
  869. }
  870. /// <summary>
  871. /// Called before the <see cref="PointerEntered"/> event occurs.
  872. /// </summary>
  873. /// <param name="e">The event args.</param>
  874. private void OnPointerEnteredCore(PointerEventArgs e)
  875. {
  876. IsPointerOver = true;
  877. OnPointerEntered(e);
  878. }
  879. /// <summary>
  880. /// Called before the <see cref="PointerExited"/> event occurs.
  881. /// </summary>
  882. /// <param name="e">The event args.</param>
  883. private void OnPointerExitedCore(PointerEventArgs e)
  884. {
  885. IsPointerOver = false;
  886. OnPointerExited(e);
  887. }
  888. /// <summary>
  889. /// Updates the <see cref="IsEffectivelyEnabled"/> property based on the parent's
  890. /// <see cref="IsEffectivelyEnabled"/>.
  891. /// </summary>
  892. /// <param name="parent">The parent control.</param>
  893. private void UpdateIsEffectivelyEnabled(InputElement? parent)
  894. {
  895. IsEffectivelyEnabled = IsEnabledCore && (parent?.IsEffectivelyEnabled ?? true);
  896. // PERF-SENSITIVE: This is called on entire hierarchy and using foreach or LINQ
  897. // will cause extra allocations and overhead.
  898. var children = VisualChildren;
  899. // ReSharper disable once ForCanBeConvertedToForeach
  900. for (int i = 0; i < children.Count; ++i)
  901. {
  902. var child = children[i] as InputElement;
  903. child?.UpdateIsEffectivelyEnabled(this);
  904. }
  905. }
  906. private void UpdatePseudoClasses(bool? isFocused, bool? isPointerOver)
  907. {
  908. if (isFocused.HasValue)
  909. {
  910. PseudoClasses.Set(":focus", isFocused.Value);
  911. PseudoClasses.Set(":focus-visible", _isFocusVisible);
  912. }
  913. if (isPointerOver.HasValue)
  914. {
  915. PseudoClasses.Set(":pointerover", isPointerOver.Value);
  916. }
  917. }
  918. }
  919. }