Skip to content

Commit fb3b4bf

Browse files
committed
[SolutionExplorer] Added Drag and Drop to solution explorer
1 parent dfcf2e9 commit fb3b4bf

File tree

7 files changed

+110
-36
lines changed

7 files changed

+110
-36
lines changed

WDE.Common.Avalonia/DnD/DragAndDrop.cs

Lines changed: 66 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections;
23
using System.Collections.Generic;
34
using System.Linq;
45
using System.Threading.Tasks;
@@ -10,6 +11,7 @@
1011
using Avalonia.Interactivity;
1112
using Avalonia.LogicalTree;
1213
using Avalonia.Media;
14+
using Avalonia.Threading;
1315
using Avalonia.VisualTree;
1416
using WDE.Common.Utils.DragDrop;
1517
using DragDropEffects = Avalonia.Input.DragDropEffects;
@@ -289,7 +291,8 @@ private static void OnTreeViewDragOver(object? sender, DragEventArgs e)
289291
if (dropHandler == null)
290292
return;
291293

292-
var parent = FindVisualParent<TreeView, TreeViewItem>(dropElement);
294+
var parent = dropElement == null ? treeView : FindVisualParent<TreeView, TreeViewItem>(dropElement);
295+
293296
ITreeItemContainerGenerator treeItemContainerGenerator;
294297
if (parent is TreeView tv)
295298
treeItemContainerGenerator = tv.ItemContainerGenerator;
@@ -298,13 +301,16 @@ private static void OnTreeViewDragOver(object? sender, DragEventArgs e)
298301
else
299302
return;
300303

301-
adorner.AddAdorner(parent);
304+
adorner.AddAdorner(treeView); // parent
302305
var indexOfDrop = treeItemContainerGenerator.IndexFromContainer(dropElement);
303306
RelativeInsertPosition insertPosition = RelativeInsertPosition.None;
304307

305308
if (dropElement != null)
306309
{
307-
var rel = e.GetPosition(dropElement).Y / dropElement.Bounds.Height;
310+
var header = dropElement.GetVisualChildren().FirstOrDefault().GetVisualChildren().FirstOrDefault();
311+
var height = header?.Bounds.Height ?? dropElement.Bounds.Height;
312+
313+
var rel = e.GetPosition(dropElement).Y / height;
308314
if (rel < 0.5f)
309315
insertPosition = RelativeInsertPosition.BeforeTargetItem;
310316
else
@@ -316,11 +322,20 @@ private static void OnTreeViewDragOver(object? sender, DragEventArgs e)
316322
else
317323
indexOfDrop = treeView.ItemCount;
318324

319-
var dropInfo = new DropInfo(dragInfo.Value.draggedElement[0]!)
325+
if (insertPosition.HasFlag(RelativeInsertPosition.AfterTargetItem) &&
326+
(dropElement?.IsExpanded ?? false) &&
327+
dropElement.ItemCount > 0)
328+
{
329+
indexOfDrop = 0;
330+
insertPosition = RelativeInsertPosition.BeforeTargetItem;
331+
dropElement = (TreeViewItem) dropElement.ItemContainerGenerator.ContainerFromIndex(0);
332+
}
333+
334+
dropInfo = new DropInfo(dragInfo.Value.draggedElement[0]!)
320335
{
321336
InsertIndex = indexOfDrop,
322337
InsertPosition = insertPosition,
323-
TargetItem = treeView.Items
338+
TargetItem = ((IControl?)dropElement)?.DataContext
324339
};
325340
dropHandler.DragOver(dropInfo);
326341

@@ -336,41 +351,48 @@ private static void OnTreeViewDragOver(object? sender, DragEventArgs e)
336351
}
337352
}*/
338353

354+
Console.WriteLine("Over " + dropElement + " (" + dropElement?.DataContext?.ToString() + ")");
355+
Console.WriteLine("Best parent: " + parent + " (" + ((IControl?)parent)?.DataContext?.ToString() + ")");
356+
Console.WriteLine("Index: " + indexOfDrop + " insert position " + insertPosition.ToString());
357+
358+
if (dropInfo.DropTargetAdorner == DropTargetAdorners.Insert)
359+
dropInfo.InsertPosition =
360+
(RelativeInsertPosition) ((int) dropInfo.InsertPosition &
361+
~(int) RelativeInsertPosition.TargetItemCenter);
339362
adorner.Adorner?.Update(treeView, treeItemContainerGenerator, dropInfo);
340363
}
364+
365+
private static IDropInfo? dropInfo;
341366

342367
private static void OnTreeViewDrop(object? sender, DragEventArgs e)
343368
{
344-
var listBox = sender as ListBox;
345-
var dropElement = FindVisualParent<ListBoxItem>(e.Source as IVisual);
369+
var treeView = sender as TreeView;
370+
var dropElement = FindVisualParent<TreeViewItem>(e.Source as IVisual);
346371
var dragInfo = e.Data.Get("") as DragInfo?;
347372
if (dragInfo == null || dragInfo.Value.draggedElement.Count == 0)
348373
return;
349374

350-
if (listBox == null)
375+
if (treeView == null)
351376
return;
352377

353-
var dropHandler = GetDropHandler(listBox);
378+
var dropHandler = GetDropHandler(treeView);
354379
if (dropHandler == null)
355380
return;
356381

357-
adorner.RemoveAdorner(listBox);
382+
adorner.RemoveAdorner(treeView);
358383

359-
var indexOfDrop = listBox.ItemContainerGenerator.IndexFromContainer(dropElement);
360-
if (dropElement != null)
361-
{
362-
var pos = e.GetPosition(dropElement);
363-
if (pos.Y > dropElement.Bounds.Height / 2)
364-
indexOfDrop++;
365-
}
366-
else
367-
indexOfDrop = listBox.ItemCount;
384+
var scrollViewer = treeView.FindDescendantOfType<ScrollViewer>();
385+
var previousOffset = scrollViewer?.Offset;
368386

369-
dropHandler.Drop(new DropInfo(dragInfo.Value.draggedElement[0]!)
387+
if (dropInfo != null)
388+
dropHandler.Drop(dropInfo);
389+
dropInfo = null;
390+
391+
Dispatcher.UIThread.Post(() =>
370392
{
371-
InsertIndex = indexOfDrop,
372-
TargetItem = listBox.Items
373-
});
393+
if (previousOffset.HasValue)
394+
scrollViewer!.Offset = previousOffset.Value;
395+
}, DispatcherPriority.Render);
374396
}
375397

376398

@@ -477,15 +499,33 @@ public void Update(TreeView treeView, ITreeItemContainerGenerator itemContainerG
477499
}
478500
else
479501
{
502+
double y = 0;
503+
IVisual parent = container.VisualParent;
504+
while (parent != null && parent != treeView)
505+
{
506+
y += parent.Bounds.Y;
507+
parent = parent.VisualParent;
508+
}
509+
510+
var header = container.GetVisualChildren().FirstOrDefault().GetVisualChildren().FirstOrDefault();
511+
var height = header?.Bounds.Height ?? container.Bounds.Height;
512+
513+
double top = container.TranslatePoint(new Point(0, 0), treeView)?.Y ?? 0;
514+
double bottom = container.TranslatePoint(new Point(0, height), treeView)?.Y ?? 0;
515+
480516
if (dropInfo.InsertPosition.HasFlag(RelativeInsertPosition.TargetItemCenter)
481517
&& dropInfo.DropTargetAdorner == DropTargetAdorners.Highlight)
482-
drawRect = new Rect(container.Bounds.X + 1, container.Bounds.Y, container.Bounds.Width - 2, container.Bounds.Height);
518+
drawRect = new Rect(container.Bounds.X + 1, top, container.Bounds.Width - 2, container.Bounds.Height);
483519
else if (dropInfo.InsertPosition.HasFlag(RelativeInsertPosition.BeforeTargetItem))
484-
drawRect = new Rect(container.Bounds.X, container.Bounds.Top, container.Bounds.Width, 1);
520+
drawRect = new Rect(container.Bounds.X, top, container.Bounds.Width, 1);
485521
else
486-
drawRect = new Rect(container.Bounds.X, container.Bounds.Bottom, container.Bounds.Width, 1);
522+
drawRect = new Rect(container.Bounds.X, bottom, container.Bounds.Width, 1);
487523
}
488524

525+
/*var scroll = treeView.FindDescendantOfType<ScrollViewer>();
526+
if (scroll != null)
527+
drawRect = new Rect(drawRect.X, drawRect.Y - scroll.Offset.Y, drawRect.Width, drawRect.Height);
528+
*/
489529
InvalidateVisual();
490530
}
491531

WDE.Common.WPF/Attached/GongDragAndDrop.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ public DropInfoAdapter(GongDrag.IDropInfo dropInfo)
154154
public int InsertIndex { get; internal set; }
155155
public CommonDrag.DropTargetAdorners DropTargetAdorner { get; set; }
156156
public CommonDrag.DragDropEffects Effects { get; set; }
157-
public CommonDrag.RelativeInsertPosition InsertPosition { get; internal set; }
157+
public CommonDrag.RelativeInsertPosition InsertPosition { get; set; }
158158
}
159159
}
160160
}

WDE.CommonViews.Avalonia/Solutions/Explorer/Views/SolutionExplorerView.axaml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
xmlns="https://github.com/avaloniaui"
88
xmlns:components="clr-namespace:WDE.Common.Avalonia.Components;assembly=WDE.Common.Avalonia"
99
xmlns:controls="clr-namespace:AvaloniaStyles.Controls;assembly=AvaloniaStyles"
10+
xmlns:dnD="clr-namespace:WDE.Common.Avalonia.DnD;assembly=WDE.Common.Avalonia"
1011
prism:ViewModelLocator.AutoWireViewModel="False" x:Name="UC">
1112

1213
<components:ToolView.Icon>
@@ -54,7 +55,12 @@
5455
</DrawingImage>
5556
</components:ToolView.Resources>
5657

57-
<TreeView x:Name="tv" Margin="0" Items="{Binding Root}" SelectedItem="{Binding SelectedItem, Mode=TwoWay}" DoubleTapped="Tv_OnDoubleTapped">
58+
<TreeView x:Name="tv" Margin="0"
59+
Items="{Binding Root}"
60+
SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
61+
PointerReleased="Tv_OnPointerReleased"
62+
dnD:DragAndDrop.IsDropTarget="True" dnD:DragAndDrop.DropHandler="{Binding }" dnD:DragAndDrop.IsDragSource="True"
63+
DoubleTapped="Tv_OnDoubleTapped">
5864
<TreeView.ContextMenu>
5965
<ContextMenu>
6066
<MenuItem Header="Add"

WDE.CommonViews.Avalonia/Solutions/Explorer/Views/SolutionExplorerView.axaml.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
using Avalonia.Interactivity;
1+
using Avalonia.Controls;
2+
using Avalonia.Controls.Presenters;
3+
using Avalonia.Input;
4+
using Avalonia.Interactivity;
25
using Avalonia.Markup.Xaml;
36
using WDE.Common.Avalonia.Components;
47
using WDE.Solutions.Explorer.ViewModels;
@@ -24,5 +27,14 @@ private void Tv_OnDoubleTapped(object? sender, RoutedEventArgs e)
2427
if (DataContext is SolutionExplorerViewModel vm && vm.SelectedItem != null)
2528
vm.RequestOpenItem.Execute(vm.SelectedItem);
2629
}
30+
31+
private void Tv_OnPointerReleased(object? sender, PointerReleasedEventArgs e)
32+
{
33+
TreeView? tv = sender as TreeView;
34+
if (tv != null && e.Source is ScrollContentPresenter)
35+
{
36+
tv.UnselectAll();
37+
}
38+
}
2739
}
2840
}

WDE.SQLEditor/ViewModels/SqlEditorViewModel.cs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Windows.Input;
1+
using System;
2+
using System.Windows.Input;
23
using AsyncAwaitBestPractices.MVVM;
34
using Prism.Commands;
45
using Prism.Mvvm;
@@ -30,8 +31,16 @@ private SqlEditorViewModel(IMySqlExecutor mySqlExecutor,
3031
async () =>
3132
{
3233
statusBar.PublishNotification(new PlainNotification(NotificationType.Info, "Executing query"));
33-
await mySqlExecutor.ExecuteSql(Code.ToString());
34-
statusBar.PublishNotification(new PlainNotification(NotificationType.Success, "Query executed"));
34+
try
35+
{
36+
await mySqlExecutor.ExecuteSql(Code.ToString());
37+
statusBar.PublishNotification(new PlainNotification(NotificationType.Success, "Query executed"));
38+
}
39+
catch (Exception e)
40+
{
41+
statusBar.PublishNotification(new PlainNotification(NotificationType.Error, "Failure during query execution"));
42+
Console.WriteLine(e);
43+
}
3544
});
3645
}, () => databaseProvider.IsConnected);
3746
IsLoading = false;

WDE.Solutions/Explorer/ViewModels/SolutionExplorerViewModel.cs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ public SolutionExplorerViewModel(ISolutionItemNameRegistry itemNameRegistry,
124124
this.solutionManager.Items.Remove(selected.Item);
125125
else
126126
selected.Parent.Item.Items?.Remove(selected.Item);
127+
SelectedItem = null;
127128
}
128129
});
129130

@@ -158,10 +159,16 @@ public SolutionExplorerViewModel(ISolutionItemNameRegistry itemNameRegistry,
158159

159160
private void DoAddItem(ISolutionItem item)
160161
{
161-
if (selected == null || selected.Item.Items == null)
162+
if (selected == null || selected.Parent == null)
162163
solutionManager.Items.Add(item);
163-
else
164+
else if (selected.Item.Items != null)
164165
selected.Item.Items.Add(item);
166+
else
167+
{
168+
var indexOf = selected.Parent.Item.Items?.IndexOf(selected.Item) ?? -1;
169+
if (indexOf != -1)
170+
selected.Parent.Item.Items!.Insert(indexOf + 1, item);
171+
}
165172

166173
if (item is not SolutionFolderItem)
167174
ea.GetEvent<EventRequestOpenItem>().Publish(item);
@@ -235,7 +242,7 @@ public void Drop(IDropInfo dropInfo)
235242
else
236243
targetItem.Parent.AddViewModel(sourceItem);
237244

238-
int destPosition = dropInfo.InsertIndex;
245+
int destPosition = dropInfo.InsertIndex + (dropInfo.InsertPosition == RelativeInsertPosition.AfterTargetItem ? 1 : 0);
239246
if (destList == sourceList && dropInfo.InsertIndex >= prevPosition)
240247
destPosition--;
241248

WoWDatabaseEditor.Common/WDE.Common/Utils/DragDrop/IDropInfo.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,6 @@ public interface IDropInfo
5959
int InsertIndex { get; }
6060
DropTargetAdorners DropTargetAdorner { get; set; }
6161
DragDropEffects Effects { get; set; }
62-
RelativeInsertPosition InsertPosition { get; }
62+
RelativeInsertPosition InsertPosition { get; set; }
6363
}
6464
}

0 commit comments

Comments
 (0)