-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DataGrid Drag-and-drop #13581
Comments
check Avalonia.Xaml.Behaviors . The samples should give you a clue how it can be implemented. |
How can I check if a DataGrid cell is being edited? To block drag-and-drop if edition is being made |
I personally would make DataGridRowHeader to be a drag moving thumb if I need it to be editable |
@timunie , thanks a lot man!! I will show here how I managed to do this, if anyone comes looking up for a solution.
<Styles
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="clr-namespace:Avalonia.Xaml.Interactivity;assembly=Avalonia.Xaml.Interactivity"
xmlns:iac="clr-namespace:Avalonia.Xaml.Interactions.Custom;assembly=Avalonia.Xaml.Interactions.Custom"
xmlns:idd="clr-namespace:Avalonia.Xaml.Interactions.DragAndDrop;assembly=Avalonia.Xaml.Interactions.DragAndDrop"
xmlns:b="using:YourNamespace.Behaviors">
<Style Selector="DataGrid.DragAndDrop">
<Setter
Property="RowHeaderWidth"
Value="24" />
</Style>
<!-- This makes only the DataGridRowHeader available for dragging, instead of making the entire row draggable -->
<!-- Which prevents a conflict between text selection in a cell and drag-and-drop -->
<Style Selector="DataGrid.DragAndDrop DataGridRowHeader">
<Setter Property="(i:Interaction.Behaviors)">
<i:BehaviorCollectionTemplate>
<i:BehaviorCollection>
<idd:ContextDragBehavior HorizontalDragThreshold="3" VerticalDragThreshold="3" />
</i:BehaviorCollection>
</i:BehaviorCollectionTemplate>
</Setter>
<Setter Property="Content">
<Template>
<Image
Margin="12,0,12,0"
Width="12"
Height="12"
VerticalAlignment="Center"
HorizontalAlignment="Center">
<Image.Source>
<!-- Use your own image here, I used this: https://www.svgrepo.com/svg/347759/grabber -->
<DrawingImage Drawing="{StaticResource IconGrabber}" />
</Image.Source>
</Image>
</Template>
</Setter>
</Style>
<Style Selector="DataGrid.MyItemsDragAndDrop">
<Style.Resources>
<b:MyItemsDataGridDropHandler x:Key="MyItemsDataGridDropHandler" />
</Style.Resources>
<Setter Property="(i:Interaction.Behaviors)">
<i:BehaviorCollectionTemplate>
<i:BehaviorCollection>
<idd:ContextDropBehavior Handler="{StaticResource MyItemsDataGridDropHandler}" />
</i:BehaviorCollection>
</i:BehaviorCollectionTemplate>
</Setter>
</Style>
</Styles>
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.VisualTree;
using Avalonia.Xaml.Interactions.DragAndDrop;
using YourNamespace.ViewModels;
namespace YourNamespace.Behaviors;
public class MyItemsDataGridDropHandler : DropHandlerBase
{
private bool Validate<T>(DataGrid dg, DragEventArgs e, object? sourceContext, object? targetContext, bool bExecute)
{
if (sourceContext is not ItemViewModel sourceItem
|| targetContext is not MainWindowViewModel vm
|| listBox.GetVisualAt(e.GetPosition(listBox)) is not Control targetControl
|| targetControl.DataContext is not ItemViewModel targetItem)
{
return false;
}
var items = vm.Items;
var sourceIndex = items.IndexOf(sourceItem);
var targetIndex = items.IndexOf(targetItem);
if (sourceIndex < 0 || targetIndex < 0)
{
return false;
}
switch (e.DragEffects)
{
case DragDropEffects.Copy:
{
if (bExecute)
{
var clone = new ItemViewModel() { Title = sourceItem.Title + "_copy" };
InsertItem(items, clone, targetIndex + 1);
}
return true;
}
case DragDropEffects.Move:
{
if (bExecute)
{
MoveItem(items, sourceIndex, targetIndex);
}
return true;
}
case DragDropEffects.Link:
{
if (bExecute)
{
SwapItem(items, sourceIndex, targetIndex);
}
return true;
}
default:
return false;
}
}
public override bool Validate(object? sender, DragEventArgs e, object? sourceContext, object? targetContext, object? state)
{
if (e.Source is Control && sender is DataGrid dg)
{
return Validate<ItemViewModel>(dg, e, sourceContext, targetContext, false);
}
return false;
}
public override bool Execute(object? sender, DragEventArgs e, object? sourceContext, object? targetContext, object? state)
{
if (e.Source is Control && sender is DataGrid dg)
{
return Validate<ItemViewModel>(dg, e, sourceContext, targetContext, true);
}
return false;
}
}
<DataGrid
Name="dgMyItems"
AutoGenerateColumns="False"
ItemsSource="{Binding Items}"
CanUserResizeColumns="True"
HeadersVisibility="All"
Classes="DragAndDrop MyItemsDragAndDrop">
...
</DataGrid> Final result: Pororoca_M2fap5KWvs.mp4 |
How can I add an icon to the first column above the drag cells? |
When using a DataGrid, I would like to perform drag-and-drop to rearrange rows.
The TreeDataGrid drag-and-drop works, but there are some bugs and required effort to migrate from DataGrid to TreeDataGrid.
@aldelaro5 showed in a discussion how to make drag-and-drop for DataGrid. I tried and it works.
However, there is a bug in the proposed solution that when someone tries to select a text from a DataGridTextCell, it understands as if the person wants to perform drag-and-drop. Basically, drag-and-drop should be disabled if a DataGrid cell is being edited.
I believe this feature is very much needed, in fact, drag-and-drop should come by default in DataGrid.
Update
There is a full working solution in the Avalonia.Xaml.Behaviors repo, check this PR
The text was updated successfully, but these errors were encountered: