Forge
csharp4405de34
1using Avalonia;
2using Avalonia.Controls;
3using Avalonia.Input;
4using Avalonia.VisualTree;
5
6namespace CascadeIDE.Services;
7
8/// <summary>
9/// Avalonia 12: у <see cref="TopLevel"/> нет <c>PointerOverElement</c>. Держим последнюю клиентскую позицию
10/// по PointerMoved / PointerEntered и вызываем <c>InputHitTest</c> на <see cref="TopLevel"/>.
11/// </summary>
12public static class UiPointerClientPosition
13{
14 private static TopLevel? _lastTopLevel;
15 private static Point _lastPoint;
16
17 public static void Attach(TopLevel topLevel)
18 {
19 topLevel.PointerMoved += (_, e) => Record(topLevel, e.GetPosition(topLevel));
20 topLevel.PointerEntered += (_, e) => Record(topLevel, e.GetPosition(topLevel));
21 }
22
23 private static void Record(TopLevel topLevel, Point clientPoint)
24 {
25 _lastTopLevel = topLevel;
26 _lastPoint = clientPoint;
27 }
28
29 public static IInputElement? TryGetPointerOver(TopLevel topLevel)
30 {
31 if (_lastTopLevel is null || !ReferenceEquals(topLevel, _lastTopLevel))
32 return null;
33 return topLevel.InputHitTest(_lastPoint);
34 }
35
36 /// <summary>Control под курсором в указанном top-level, если последнее событие указателя было в нём.</summary>
37 public static Control? TryGetControlUnderPointer(TopLevel topLevel) =>
38 ControlFromHit(TryGetPointerOver(topLevel));
39
40 /// <summary>Control под курсором в том окне, куда последним пришёл PointerMoved.</summary>
41 public static Control? TryGetPointerOverControlAnywhere()
42 {
43 if (_lastTopLevel is null)
44 return null;
45 return ControlFromHit(_lastTopLevel.InputHitTest(_lastPoint));
46 }
47
48 /// <summary>Результат хит-теста → ближайший <see cref="Control"/> (сам элемент или предок).</summary>
49 public static Control? ControlFromHit(IInputElement? hit) =>
50 hit as Control ?? NearestAncestorControl(hit as Visual);
51
52 private static Control? NearestAncestorControl(Visual? visual)
53 {
54 for (var v = visual?.GetVisualParent(); v is not null; v = v.GetVisualParent())
55 {
56 if (v is Control c)
57 return c;
58 }
59 return null;
60 }
61}
62
View only · write via MCP/CIDE