Skip to content
This repository has been archived by the owner on Nov 1, 2024. It is now read-only.

Commit

Permalink
Merge pull request #143 from alexandrehtrb/samples/datagrid-drag-and-…
Browse files Browse the repository at this point in the history
…drop

samples: add sample for DataGrid drag-and-drop
  • Loading branch information
wieslawsoltes authored Apr 2, 2024
2 parents 0f87e47 + 419f3d2 commit b58d0e4
Show file tree
Hide file tree
Showing 5 changed files with 152 additions and 0 deletions.
1 change: 1 addition & 0 deletions samples/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Avalonia" Version="$(AvaloniaVersion)" />
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="$(AvaloniaVersion)" />
<PackageVersion Include="Avalonia.Desktop" Version="$(AvaloniaVersion)" />
<PackageVersion Include="Avalonia.Diagnostics" Version="$(AvaloniaVersion)" />
<PackageVersion Include="Avalonia.ReactiveUI" Version="$(AvaloniaVersion)" />
Expand Down
1 change: 1 addition & 0 deletions samples/DragAndDropSample/App.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@

<Application.Styles>
<FluentTheme />
<StyleInclude Source="avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml"/>
</Application.Styles>
</Application>
79 changes: 79 additions & 0 deletions samples/DragAndDropSample/Behaviors/ItemsDataGridDropHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.VisualTree;
using Avalonia.Xaml.Interactions.DragAndDrop;
using DragAndDropSample.ViewModels;

namespace DragAndDropSample.Behaviors;

public class ItemsDataGridDropHandler : DropHandlerBase
{
private bool Validate<T>(DataGrid dg, DragEventArgs e, object? sourceContext, object? targetContext, bool bExecute) where T : ItemViewModel
{
if (sourceContext is not T sourceItem
|| targetContext is not MainWindowViewModel vm
|| dg.GetVisualAt(e.GetPosition(dg)) is not Control targetControl
|| targetControl.DataContext is not T 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;
}
}
1 change: 1 addition & 0 deletions samples/DragAndDropSample/DragAndDropSample.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

<ItemGroup>
<PackageReference Include="Avalonia" />
<PackageReference Include="Avalonia.Controls.DataGrid" />
<PackageReference Include="Avalonia.Desktop" />
<PackageReference Include="Avalonia.Diagnostics" />
<PackageReference Include="Avalonia.Themes.Fluent" />
Expand Down
70 changes: 70 additions & 0 deletions samples/DragAndDropSample/Views/MainWindow.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@
<vm:MainWindowViewModel />
</Design.DataContext>

<Window.Resources>
<!-- IconGrabber, MIT License, author: Primer, taken from: https://www.svgrepo.com/svg/347759/grabber -->
<PathGeometry x:Key="IconGrabberGeometry">M15 18a1 1 0 100-2 1 1 0 000 2zm1-6a1 1 0 11-2 0 1 1 0 012 0zm-7 6a1 1 0 100-2 1 1 0 000 2zm0-5a1 1 0 100-2 1 1 0 000 2zm7-6a1 1 0 11-2 0 1 1 0 012 0zM9 8a1 1 0 100-2 1 1 0 000 2z</PathGeometry>
<GeometryDrawing x:Key="IconGrabber" Brush="Black" Geometry="{StaticResource IconGrabberGeometry}" />
</Window.Resources>

<Window.Styles>

<Style Selector="ListBox.ItemsDragAndDrop">
Expand Down Expand Up @@ -89,6 +95,49 @@
</i:BehaviorCollectionTemplate>
</Setter>
</Style>

<Style Selector="DataGrid.DragAndDrop">
<Style.Resources>
<b:ItemsDataGridDropHandler x:Key="ItemsDataGridDropHandler" />
</Style.Resources>
<Setter
Property="RowHeaderWidth"
Value="24" />
<Setter Property="(i:Interaction.Behaviors)">
<i:BehaviorCollectionTemplate>
<i:BehaviorCollection>
<idd:ContextDropBehavior Handler="{StaticResource ItemsDataGridDropHandler}" />
</i:BehaviorCollection>
</i:BehaviorCollectionTemplate>
</Setter>
</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>

</Window.Styles>

Expand Down Expand Up @@ -129,6 +178,27 @@
</ListBox>
</TabItem>

<TabItem Header="DataGrid">
<Grid>
<DataGrid
AutoGenerateColumns="False"
ItemsSource="{Binding Items}"
CanUserResizeColumns="True"
HeadersVisibility="All"
Classes="DragAndDrop">
<DataGrid.Columns>
<DataGridTextColumn
Width="*"
Binding="{Binding Title}">
<DataGridTextColumn.Header>
<TextBlock Text="Title"/>
</DataGridTextColumn.Header>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</TabItem>

</TabControl>

</Window>

0 comments on commit b58d0e4

Please sign in to comment.