Files
CryptoProfile-Tracker/CryptoPortfolio Tracker/Behaviors/WindowsDragBehavior.cs
T

124 lines
3.6 KiB
C#

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<bool> EnableWindowDragProperty =
AvaloniaProperty.RegisterAttached<Control, bool>(
"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<Control>(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<Border>(control, "PART_NavigationBar");
if (topBar is null)
return;
topBar.AddHandler(
InputElement.PointerPressedEvent,
OnTopBarPointerPressed,
RoutingStrategies.Tunnel);
}
private static void Detach(Control control)
{
var topBar = FindInVisualTree<Border>(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<T>(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<T>(child, name);
if (result is not null)
return result;
}
return null;
}
}