[Avalonia.Native] Use relative placement for detecting drag and drop locations. (#20280)
* Use relative position of view for drag and drop * Add Drag And Drop Test * Add AutomationProperties
This commit is contained in:
@@ -82,6 +82,7 @@ namespace IntegrationTestApp
|
||||
new("ComboBox", () => new ComboBoxPage()),
|
||||
new("ContextMenu", () => new ContextMenuPage()),
|
||||
new("DesktopPage", () => new DesktopPage()),
|
||||
new("DragDrop", () => new DragDropPage()),
|
||||
new("Embedding", () => new EmbeddingPage()),
|
||||
new("Gestures", () => new GesturesPage()),
|
||||
new("ListBox", () => new ListBoxPage()),
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="IntegrationTestApp.Pages.DragDropPage">
|
||||
<DockPanel>
|
||||
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Margin="4">
|
||||
<Button Name="ResetDragDrop" Click="ResetDragDrop_Click" Margin="0,0,8,0">Reset</Button>
|
||||
<TextBlock VerticalAlignment="Center">Drop Position: </TextBlock>
|
||||
<TextBlock Name="DropPosition" VerticalAlignment="Center" Margin="4,0"/>
|
||||
<TextBlock VerticalAlignment="Center" Margin="8,0,0,0">Status: </TextBlock>
|
||||
<TextBlock Name="DragDropStatus" VerticalAlignment="Center" Margin="4,0"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Use a Grid with row definitions to create offset from window origin -->
|
||||
<!-- The top spacer ensures the drag/drop controls are NOT at (0,0) -->
|
||||
<Grid RowDefinitions="100,*">
|
||||
<!-- Spacer row to offset controls from window origin -->
|
||||
<Border Grid.Row="0" Background="LightGray">
|
||||
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
Text="Spacer (100px) - Controls below are offset from window origin"/>
|
||||
</Border>
|
||||
|
||||
<!-- Drag and Drop test area -->
|
||||
<Grid Grid.Row="1" ColumnDefinitions="*,*" Margin="20">
|
||||
<!-- Drag Source -->
|
||||
<Border Name="DragSource"
|
||||
Grid.Column="0"
|
||||
Background="CornflowerBlue"
|
||||
Margin="10"
|
||||
CornerRadius="8"
|
||||
AutomationProperties.AccessibilityView="Content"
|
||||
PointerPressed="DragSource_PointerPressed">
|
||||
<TextBlock HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Text="Drag Source"
|
||||
Foreground="White"
|
||||
FontWeight="Bold"/>
|
||||
</Border>
|
||||
|
||||
<!-- Drop Target -->
|
||||
<Border Name="DropTarget"
|
||||
Grid.Column="1"
|
||||
Background="LightGreen"
|
||||
Margin="10"
|
||||
CornerRadius="8"
|
||||
AutomationProperties.AccessibilityView="Content"
|
||||
DragDrop.AllowDrop="True">
|
||||
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||
<TextBlock Text="Drop Target"
|
||||
HorizontalAlignment="Center"
|
||||
FontWeight="Bold"/>
|
||||
<TextBlock Name="DropTargetText"
|
||||
HorizontalAlignment="Center"
|
||||
Text="Drop items here"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</DockPanel>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,103 @@
|
||||
using System;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Input.Platform;
|
||||
using Avalonia.Interactivity;
|
||||
|
||||
namespace IntegrationTestApp.Pages;
|
||||
|
||||
public partial class DragDropPage : UserControl
|
||||
{
|
||||
public DragDropPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
// Set up drag-drop event handlers
|
||||
AddHandler(DragDrop.DragOverEvent, DropTarget_DragOver);
|
||||
AddHandler(DragDrop.DropEvent, DropTarget_Drop);
|
||||
}
|
||||
|
||||
private async void DragSource_PointerPressed(object? sender, PointerPressedEventArgs e)
|
||||
{
|
||||
if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
|
||||
{
|
||||
var dragData = new DataTransfer();
|
||||
dragData.Add(DataTransferItem.CreateText("TestDragData"));
|
||||
|
||||
DragDropStatus.Text = "Dragging...";
|
||||
|
||||
var result = await DragDrop.DoDragDropAsync(e, dragData, DragDropEffects.Copy | DragDropEffects.Move);
|
||||
|
||||
DragDropStatus.Text = result switch
|
||||
{
|
||||
DragDropEffects.Copy => "Copied",
|
||||
DragDropEffects.Move => "Moved",
|
||||
DragDropEffects.None => "Cancelled",
|
||||
_ => $"Result: {result}"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private void DropTarget_DragOver(object? sender, DragEventArgs e)
|
||||
{
|
||||
// Only handle events for the drop target
|
||||
if (e.Source != DropTarget && !IsChildOf(e.Source as Visual, DropTarget))
|
||||
return;
|
||||
|
||||
e.DragEffects = DragDropEffects.Copy;
|
||||
|
||||
// Get the position relative to the drop target
|
||||
var position = e.GetPosition(DropTarget);
|
||||
DropPosition.Text = $"DragOver: ({position.X:F0}, {position.Y:F0})";
|
||||
}
|
||||
|
||||
private void DropTarget_Drop(object? sender, DragEventArgs e)
|
||||
{
|
||||
// Only handle events for the drop target
|
||||
if (e.Source != DropTarget && !IsChildOf(e.Source as Visual, DropTarget))
|
||||
return;
|
||||
|
||||
// Get the position relative to the drop target
|
||||
var position = e.GetPosition(DropTarget);
|
||||
DropPosition.Text = $"Drop: ({position.X:F0}, {position.Y:F0})";
|
||||
|
||||
// Check if the position is within reasonable bounds of the drop target
|
||||
var bounds = DropTarget.Bounds;
|
||||
var isWithinBounds = position.X >= 0 && position.X <= bounds.Width &&
|
||||
position.Y >= 0 && position.Y <= bounds.Height;
|
||||
|
||||
var text = e.DataTransfer.TryGetText();
|
||||
if (text != null)
|
||||
{
|
||||
DropTargetText.Text = isWithinBounds
|
||||
? $"Dropped: {text} at ({position.X:F0}, {position.Y:F0})"
|
||||
: $"ERROR: Position out of bounds! ({position.X:F0}, {position.Y:F0})";
|
||||
DragDropStatus.Text = isWithinBounds ? "Drop OK" : "Drop position ERROR";
|
||||
}
|
||||
|
||||
e.DragEffects = DragDropEffects.Copy;
|
||||
}
|
||||
|
||||
private static bool IsChildOf(Visual? child, Visual? parent)
|
||||
{
|
||||
if (child == null || parent == null)
|
||||
return false;
|
||||
|
||||
var current = child.Parent as Visual;
|
||||
while (current != null)
|
||||
{
|
||||
if (current == parent)
|
||||
return true;
|
||||
current = current.Parent as Visual;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void ResetDragDrop_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
DropPosition.Text = string.Empty;
|
||||
DragDropStatus.Text = string.Empty;
|
||||
DropTargetText.Text = "Drop items here";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user