using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Primitives; using Avalonia.Input; using Avalonia.Interactivity; using Avalonia.VisualTree; namespace CryptoPortfolio_Tracker.Behaviors; public static class WindowDragBehavior { public static readonly AttachedProperty EnableWindowDragProperty = AvaloniaProperty.RegisterAttached( "EnableWindowDrag", typeof(WindowDragBehavior)); public static bool GetEnableWindowDrag(Control element) => element.GetValue(EnableWindowDragProperty); public static void SetEnableWindowDrag(Control element, bool value) => element.SetValue(EnableWindowDragProperty, value); static WindowDragBehavior() { EnableWindowDragProperty.Changed.AddClassHandler(OnEnableWindowDragChanged); } private static void OnEnableWindowDragChanged(Control control, AvaloniaPropertyChangedEventArgs e) { if (e.NewValue is true) { // Контрол ещё может не быть в визуальном дереве if (control.IsLoaded) Attach(control); else control.Loaded += OnControlLoaded; } else { control.Loaded -= OnControlLoaded; Detach(control); } } private static void OnControlLoaded(object? sender, RoutedEventArgs e) { if (sender is Control control) { control.Loaded -= OnControlLoaded; Attach(control); } } private static void Attach(Control control) { var topBar = FindInVisualTree(control, "PART_NavigationBar"); if (topBar is null) return; topBar.AddHandler( InputElement.PointerPressedEvent, OnTopBarPointerPressed, RoutingStrategies.Tunnel); } private static void Detach(Control control) { var topBar = FindInVisualTree(control, "Border#PART_NavigationBar"); if (topBar is null) return; topBar.RemoveHandler( InputElement.PointerPressedEvent, OnTopBarPointerPressed); } private static void OnTopBarPointerPressed(object? sender, PointerPressedEventArgs e) { if (!e.GetCurrentPoint(null).Properties.IsLeftButtonPressed) return; // Проверяем — нажатие было на кнопке или интерактивном элементе? if (e.Source is Visual source && IsInteractiveElement(source)) return; if (sender is Visual visual && TopLevel.GetTopLevel(visual) is Window window) { window.BeginMoveDrag(e); } } private static bool IsInteractiveElement(Visual visual) { Visual? current = visual; while (current is not null) { if (current is Button or ToggleButton or CheckBox or RadioButton or Slider or TextBox or ComboBox) return true; if (current is Border { Name: "Border#PART_NavigationBar" }) break; current = current.GetVisualParent(); } return false; } private static T? FindInVisualTree(Visual root, string name) where T : Visual { if (root is T typed && root.Name == name) return typed; foreach (var child in root.GetVisualChildren()) { var result = FindInVisualTree(child, name); if (result is not null) return result; } return null; } }