private bool IsValidDrop(DragEventArgs e, out DropInfo dropInfo) { dropInfo = null; IDataSourceViewModel viewModel = e.Data.GetData(typeof (SingleDataSourceViewModel)) as IDataSourceViewModel ?? e.Data.GetData(typeof (MergedDataSourceViewModel)) as IDataSourceViewModel; var source = new TreeItem { ViewModel = viewModel }; if (source.ViewModel == null) return false; TreeItem dropTarget = GetDataSourceFromPosition(e.GetPosition(_partDataSources)); if (dropTarget == null) return false; DataSourceDropType dropType = GetDropType(e, dropTarget, viewModel); var model = (MainWindowViewModel) DataContext; IDataSourceViewModel group; if (!model.CanBeDropped(source.ViewModel, dropTarget.ViewModel, dropType, out group)) return false; dropInfo = new DropInfo { Source = source, Type = dropType, Target = dropTarget, TargetGroup = new TreeItem { ViewModel = group, TreeViewItem = GetTreeViewItem(group) } }; return true; }
private DataSourceDropType GetDropType(DragEventArgs e, TreeItem destination, IDataSourceViewModel source) { if (destination == null) return DataSourceDropType.None; Point pos = e.GetPosition(destination.TreeViewItem); var dropType = DataSourceDropType.None; double height = destination.TreeViewItem.ActualHeight; if (source is SingleDataSourceViewModel) { // Let's distribute it as follows: // 20% top => arrange // 60% middle => group // 20% bottom => arrange // // This way 60% of the height is used for grouping and 40% is used for arranging. if (pos.Y < height*0.2) dropType |= DataSourceDropType.ArrangeTop; else if (pos.Y < height*0.8) dropType |= DataSourceDropType.Group; else dropType |= DataSourceDropType.ArrangeBottom; if (destination.ViewModel.Parent != null) dropType |= DataSourceDropType.Group; } else { // Groups can't be grouped any further, thus we // simply arrange it above or beneath the drop source // at a 50/50 split. if (pos.Y < height*0.5) dropType |= DataSourceDropType.ArrangeTop; else dropType |= DataSourceDropType.ArrangeBottom; } return dropType; }