Skip to content

Commit

Permalink
[SolutionExplorer] Implemented proper drag and drop in solution explorer
Browse files Browse the repository at this point in the history
  • Loading branch information
BAndysc committed Jan 11, 2021
1 parent 57387fd commit 57ee4de
Show file tree
Hide file tree
Showing 4 changed files with 164 additions and 21 deletions.
94 changes: 87 additions & 7 deletions WDE.Solutions/Explorer/ViewModels/SolutionExplorerViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using GongSolutions.Wpf.DragDrop;
using Prism.Events;
using WDE.Common;
using WDE.Common.Events;
Expand All @@ -15,11 +16,12 @@

namespace WDE.Solutions.Explorer.ViewModels
{
public class SolutionExplorerViewModel : BindableBase, ITool
public class SolutionExplorerViewModel : BindableBase, ITool, IDropTarget
{
private readonly ISolutionItemNameRegistry itemNameRegistry;
private readonly ISolutionManager _solutionManager;
private readonly IEventAggregator _ea;
private readonly IStatusBar _statusBar;

private ObservableCollection<SolutionItemViewModel> _firstGeneration;
public ObservableCollection<SolutionItemViewModel> Root => _firstGeneration;
Expand All @@ -33,11 +35,17 @@ public class SolutionExplorerViewModel : BindableBase, ITool
private SolutionItemViewModel _selected;
private Dictionary<ISolutionItem, SolutionItemViewModel> _itemToViewmodel;

public SolutionExplorerViewModel(ISolutionItemNameRegistry itemNameRegistry, ISolutionManager solutionManager, IEventAggregator ea, INewItemService newItemService, ISolutionItemSqlGeneratorRegistry sqlGeneratorRegistry)
public SolutionExplorerViewModel(ISolutionItemNameRegistry itemNameRegistry,
ISolutionManager solutionManager,
IEventAggregator ea,
INewItemService newItemService,
IStatusBar statusBar,
ISolutionItemSqlGeneratorRegistry sqlGeneratorRegistry)
{
this.itemNameRegistry = itemNameRegistry;
_solutionManager = solutionManager;
_ea = ea;
_statusBar = statusBar;

_firstGeneration = new ObservableCollection<SolutionItemViewModel>();
_itemToViewmodel = new Dictionary<ISolutionItem, SolutionItemViewModel>();
Expand All @@ -50,8 +58,14 @@ public SolutionExplorerViewModel(ISolutionItemNameRegistry itemNameRegistry, ISo
_solutionManager.Items.CollectionChanged += (sender, args) =>
{
if (args.NewItems != null)
{
int i = 0;
foreach (var obj in args.NewItems)
AddItemToRoot(obj as ISolutionItem);
{
AddItemToRoot(obj as ISolutionItem, args.NewStartingIndex + i);
i++;
}
}

if (args.OldItems != null)
foreach (var obj in args.OldItems)
Expand Down Expand Up @@ -108,11 +122,16 @@ public SolutionExplorerViewModel(ISolutionItemNameRegistry itemNameRegistry, ISo
});
}

private void AddItemToRoot(ISolutionItem item)
private void AddItemToRoot(ISolutionItem item, int index = -1)
{
var viewModel = new SolutionItemViewModel(itemNameRegistry, item);
_itemToViewmodel.Add(item, viewModel);
Root.Add(viewModel);
if (!_itemToViewmodel.TryGetValue(item, out var viewModel))
{
viewModel = new SolutionItemViewModel(itemNameRegistry, item);
_itemToViewmodel[item] = viewModel;
}
else
viewModel.Parent = null;
Root.Insert(index < 0 ? Root.Count : index, viewModel);
}

public string Title { get; } = "Solution explorer";
Expand All @@ -122,5 +141,66 @@ public Visibility Visibility
get => _visibility;
set => SetProperty(ref _visibility, value);
}

public void DragOver(IDropInfo dropInfo)
{
SolutionItemViewModel sourceItem = dropInfo.Data as SolutionItemViewModel;
SolutionItemViewModel targetItem = dropInfo.TargetItem as SolutionItemViewModel;

if (sourceItem != null)
{
var highlight = dropInfo.InsertPosition.HasFlag(RelativeInsertPosition.TargetItemCenter) &&
(targetItem?.IsContainer ?? false);

dropInfo.DropTargetAdorner = highlight ? DropTargetAdorners.Highlight : DropTargetAdorners.Insert;
dropInfo.Effects = DragDropEffects.Move;
}
}

public void Drop(IDropInfo dropInfo)
{
SolutionItemViewModel sourceItem = dropInfo.Data as SolutionItemViewModel;
SolutionItemViewModel targetItem = dropInfo.TargetItem as SolutionItemViewModel;

if (sourceItem == null)
return;

int prevPosition = 0;
var sourceList = sourceItem.Parent == null ? _solutionManager.Items : sourceItem.Parent.Item.Items;
var destListOwner = (dropInfo.DropTargetAdorner == DropTargetAdorners.Highlight)
? targetItem
: targetItem?.Parent;
var destList = destListOwner?.Item?.Items ?? _solutionManager.Items;

while (destListOwner != null)
{
if (sourceItem.Item == destListOwner.Item)
return;
destListOwner = destListOwner.Parent;
}

prevPosition = sourceList.IndexOf(sourceItem.Item);
if (prevPosition >= 0)
sourceList.RemoveAt(prevPosition);

if (dropInfo.DropTargetAdorner == DropTargetAdorners.Highlight)
{
targetItem.AddViewModel(sourceItem);
targetItem.Item.Items.Add(sourceItem.Item);
}
else
{
if (targetItem == null || targetItem.Parent == null)
_itemToViewmodel[sourceItem.Item] = sourceItem;
else
targetItem.Parent.AddViewModel(sourceItem);

var destPosition = dropInfo.InsertIndex;
if (destList == sourceList && dropInfo.InsertIndex >= prevPosition)
destPosition--;

destList.Insert(destPosition, sourceItem.Item);
}
}
}
}
43 changes: 33 additions & 10 deletions WDE.Solutions/Explorer/ViewModels/SolutionItemViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class SolutionItemViewModel : BindableBase
private ISolutionItemNameRegistry itemNameRegistry;

private readonly ISolutionItem _item;
private readonly SolutionItemViewModel _parent;
private SolutionItemViewModel _parent;

private readonly ObservableCollection<SolutionItemViewModel> _children;
public ObservableCollection<SolutionItemViewModel> Children => _children;
Expand All @@ -26,14 +26,24 @@ public class SolutionItemViewModel : BindableBase
public bool IsContainer => _item.IsContainer;
public bool IsExportable => _item.IsExportable;
public ISolutionItem Item => _item;
public SolutionItemViewModel Parent => _parent;
public SolutionItemViewModel Parent
{
get => _parent;
set => _parent = value;
}

private bool _isSelected;

public bool IsSelected
{
get { return _isSelected; }
set { SetProperty(ref _isSelected, value); }
get => _isSelected;
set => SetProperty(ref _isSelected, value);
}

private bool _isExpanded;
public bool IsExpanded
{
get => _isExpanded;
set => SetProperty(ref _isExpanded, value);
}

public SolutionItemViewModel(ISolutionItemNameRegistry itemNameRegistry, ISolutionItem item) : this(itemNameRegistry, item, null)
Expand All @@ -58,8 +68,11 @@ public SolutionItemViewModel(ISolutionItemNameRegistry itemNameRegistry, ISoluti
item.Items.CollectionChanged += (sender, args) =>
{
if (args.NewItems != null)
{
int i = 0;
foreach (object obj in args.NewItems)
AddItem(obj as ISolutionItem);
AddItem(obj as ISolutionItem, args.NewStartingIndex + i);
}

if (args.OldItems != null)
foreach (object obj in args.OldItems)
Expand All @@ -72,11 +85,21 @@ public SolutionItemViewModel(ISolutionItemNameRegistry itemNameRegistry, ISoluti
}
}

private void AddItem(ISolutionItem item)
private void AddItem(ISolutionItem item, int index = -1)
{
if (!_itemToViewmodel.TryGetValue(item, out var viewModel))
{
viewModel = new SolutionItemViewModel(itemNameRegistry, item, this);
_itemToViewmodel[item] = viewModel;
}
else
viewModel.Parent = this;
_children.Insert(index < 0 ? _children.Count : index, viewModel);
}

public void AddViewModel(SolutionItemViewModel sourceItem)
{
var viewModel = new SolutionItemViewModel(itemNameRegistry, item, this);
_children.Add(viewModel);
_itemToViewmodel.Add(item, viewModel);
_itemToViewmodel[sourceItem.Item] = sourceItem;
}
}
}
33 changes: 29 additions & 4 deletions WDE.Solutions/Explorer/Views/SolutionExplorerView.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:dd="urn:gong-wpf-dragdrop"
xmlns:helpers="clr-namespace:WDE.Solutions.Explorer.Helpers"
xmlns:system="clr-namespace:System;assembly=System.Runtime"
prism:ViewModelLocator.AutoWireViewModel="True" x:Name="UC">
<UserControl.Resources>

Expand Down Expand Up @@ -190,7 +191,7 @@
<Grid>


<TreeView x:Name="tv" ItemsSource="{Binding Root}" dd:DragDrop.IsDragSource="True" dd:DragDrop.IsDropTarget="True">
<TreeView x:Name="tv" ItemsSource="{Binding Root}" dd:DragDrop.IsDragSource="True" dd:DragDrop.IsDropTarget="True" dd:DragDrop.DropHandler="{Binding}">

<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectedItemChanged">
Expand All @@ -204,6 +205,8 @@
<TreeView.ItemContainerStyle>
<Style BasedOn="{StaticResource TreeViewFullRow}" TargetType="{x:Type TreeViewItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}"/>

<Setter Property="Tag" Value="{Binding RelativeSource={RelativeSource AncestorType=UserControl}}" />

<!--<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
Expand All @@ -223,9 +226,31 @@
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding ExtraId}" FontFamily="Consolas" Background="{DynamicResource ContentSpecialBackground}" Foreground="{DynamicResource ContentSpecialForeground}" Margin="0,0,7,0">
</TextBlock>
<TextBlock Text="{Binding Name}" />
<Image Width="14" Height="14" Margin="0,0,6,0">
<Image.Style>
<Style TargetType="Image">
<Style.Triggers>
<DataTrigger Binding="{Binding IsContainer}">
<DataTrigger.Value><system:Boolean>True</system:Boolean></DataTrigger.Value>
<Setter Property="Source" Value="{DynamicResource Folder}"></Setter>
</DataTrigger>
</Style.Triggers>
<Setter Property="Source" Value="{DynamicResource File}"></Setter>
</Style>
</Image.Style>
</Image>
<Label Padding="2" VerticalContentAlignment="Center" Content="{Binding ExtraId}" FontFamily="Consolas" Background="{DynamicResource ContentSpecialBackground}" Foreground="{DynamicResource ContentSpecialForeground}" Margin="0,0,7,0">
<Label.Style>
<Style TargetType="Label">
<Style.Triggers>
<DataTrigger Binding="{Binding ExtraId}" Value="{x:Null}">
<Setter Property="Visibility" Value="Collapsed"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Label.Style>
</Label>
<Label Margin="0,0,0,0" Padding="0,0,0,0" VerticalContentAlignment="Center" Content="{Binding Name}" />
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
Expand Down
15 changes: 15 additions & 0 deletions WoWDatabaseEditor/Themes/BlueTheme.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -188,4 +188,19 @@
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="Folder">
<DrawingImage.Drawing>
<DrawingGroup ClipGeometry="M0,0 V20 H20 V0 H0 Z">
<GeometryDrawing Brush="#4FCAE6" Geometry="F1 M20,20z M0,0z M8,2L2,2C0.9,2,0,2.9,0,4L0,16C0,17.1,0.9,18,2,18L18,18C19.1,18,20,17.1,20,16L20,6C20,4.9,19.1,4,18,4L10,4 8,2z" />
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="File">
<DrawingImage.Drawing>
<DrawingGroup ClipGeometry="M0,0 V16 H16 V0 H0 Z">
<GeometryDrawing Brush="#FF575757" Geometry="F0 M16,16z M0,0z M14,4L14,13.913 13,15 3,15 2,14 2,2 3,1 12,1 14,4z M3.394,1.95L2.95,2.394 2.95,13.606 3.394,14.05 12.583,14.05 13.05,13.542 13.05,4.288 11.492,1.95 3.394,1.95z" />
<GeometryDrawing Brush="#FF575757" Geometry="F0 M16,16z M0,0z M11,1L11,4 14,4 11,1z" />
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
</ResourceDictionary>

0 comments on commit 57ee4de

Please sign in to comment.