├── src ├── gong.public.snk ├── GongSolutions.WPF.DragDrop │ ├── Icons │ │ ├── EffectCopy.png │ │ ├── EffectLink.png │ │ ├── EffectMove.png │ │ ├── EffectNone.png │ │ └── IconFactory.cs │ ├── EventType.cs │ ├── ScrollingMode.cs │ ├── IDragItemSource.cs │ ├── GongSolutions.WPF.DragDrop.csproj │ ├── Utilities │ │ ├── IRootElementFinder.cs │ │ ├── RootElementFinder.cs │ │ ├── TreeViewItemExtensions.cs │ │ ├── MouseHelper.cs │ │ ├── DpiHelper.cs │ │ ├── TypeUtilities.cs │ │ ├── WindowStyleHelper.cs │ │ ├── DragDropExtensions.cs │ │ ├── HitTestUtilities.cs │ │ └── VisualTreeExtensions.cs │ ├── IDragPreviewItemsSorter.cs │ ├── ICloneableDragItem.cs │ ├── IDropTargetItemsSorter.cs │ ├── DropHintState.cs │ ├── DropTargetAdorners.cs │ ├── DragDropEffectPreview.cs │ ├── DropHintInfo.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── Directory.Build.props │ ├── IDropInfoBuilder.cs │ ├── IDragInfoBuilder.cs │ ├── IDropHintInfo.cs │ ├── DropTargetHintWeakReference.cs │ ├── Directory.build.targets │ ├── DefaultDragHandler.cs │ ├── DropHintData.cs │ ├── IDropTarget.cs │ ├── DropTargetAdorner.cs │ ├── IDragSource.cs │ ├── DropTargetHighlightAdorner.cs │ ├── IDragInfo.cs │ ├── DropTargetHintAdorner.cs │ └── IDropInfo.cs ├── Showcase │ ├── FodyWeavers.xml │ ├── App.xaml.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── Views │ │ ├── Issues.xaml.cs │ │ ├── ListBoxSamples.xaml.cs │ │ ├── ListViewSamples.xaml.cs │ │ ├── DataGridSamples.xaml.cs │ │ ├── TabControlSamples.xaml.cs │ │ ├── MixedSamples.xaml.cs │ │ ├── TreeViewSamples.xaml.cs │ │ ├── SettingsView.xaml.cs │ │ ├── DataGridSamples.xaml │ │ └── SettingsView.xaml │ ├── Models │ │ ├── DataGridRowModel.cs │ │ ├── TabItemModel.cs │ │ ├── FilesDropHandler.cs │ │ ├── DragAdornerTemplateSelector.cs │ │ ├── ClonableItemModel.cs │ │ ├── ListBoxCustomDropHandler.cs │ │ ├── NestedDropHandler.cs │ │ ├── GroupedItem.cs │ │ ├── GroupedDropHandler.cs │ │ ├── SerializableDragHandler.cs │ │ ├── TreeNode.cs │ │ ├── CustomDropHintHandler.cs │ │ ├── TextBoxCustomDropHandler.cs │ │ ├── ItemModel.cs │ │ ├── SampleData.cs │ │ └── SerializableDropHandler.cs │ ├── ViewModels │ │ ├── ViewModelBase.cs │ │ ├── SimpleCommand.cs │ │ └── MainViewModel.cs │ ├── CustomControls │ │ └── CustomListBox.cs │ ├── MainWindow.xaml.cs │ ├── MainWindow.xaml │ ├── Showcase.WPF.DragDrop.csproj │ └── app.manifest ├── Directory.build.targets ├── Directory.packages.props ├── Directory.build.props └── GongSolutions.WPF.DragDrop.sln ├── screenshots ├── gong_240.gif ├── DragHint-Demo.gif ├── DragDropSample01.gif ├── 2016-09-03_00h51_35.png ├── 2016-09-03_00h52_20.png ├── 2016-09-03_00h53_03.png └── 2016-09-03_00h53_21.png ├── GongSolutions.Wpf.DragDrop.png ├── GongSolutions.Wpf.DragDrop.Full.png ├── .github ├── PULL_REQUEST_TEMPLATE.md ├── FUNDING.yml ├── dependabot.yml ├── ISSUE_TEMPLATE │ └── bug_report.md ├── workflows │ └── ci.yml ├── ISSUE_TEMPLATE.md └── CONTRIBUTING.md ├── global.json ├── .config └── dotnet-tools.json ├── .editorconfig ├── cake.config ├── GitVersion.yml ├── NuGet.Config ├── .gitattributes ├── GitReleaseManager.yaml ├── .vscode ├── launch.json └── tasks.json ├── appveyor.yml ├── NOTICE.md ├── LICENSE ├── Settings.XAMLStyler ├── README.md └── .gitignore /src/gong.public.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/punker76/gong-wpf-dragdrop/HEAD/src/gong.public.snk -------------------------------------------------------------------------------- /screenshots/gong_240.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/punker76/gong-wpf-dragdrop/HEAD/screenshots/gong_240.gif -------------------------------------------------------------------------------- /GongSolutions.Wpf.DragDrop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/punker76/gong-wpf-dragdrop/HEAD/GongSolutions.Wpf.DragDrop.png -------------------------------------------------------------------------------- /screenshots/DragHint-Demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/punker76/gong-wpf-dragdrop/HEAD/screenshots/DragHint-Demo.gif -------------------------------------------------------------------------------- /screenshots/DragDropSample01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/punker76/gong-wpf-dragdrop/HEAD/screenshots/DragDropSample01.gif -------------------------------------------------------------------------------- /GongSolutions.Wpf.DragDrop.Full.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/punker76/gong-wpf-dragdrop/HEAD/GongSolutions.Wpf.DragDrop.Full.png -------------------------------------------------------------------------------- /screenshots/2016-09-03_00h51_35.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/punker76/gong-wpf-dragdrop/HEAD/screenshots/2016-09-03_00h51_35.png -------------------------------------------------------------------------------- /screenshots/2016-09-03_00h52_20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/punker76/gong-wpf-dragdrop/HEAD/screenshots/2016-09-03_00h52_20.png -------------------------------------------------------------------------------- /screenshots/2016-09-03_00h53_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/punker76/gong-wpf-dragdrop/HEAD/screenshots/2016-09-03_00h53_03.png -------------------------------------------------------------------------------- /screenshots/2016-09-03_00h53_21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/punker76/gong-wpf-dragdrop/HEAD/screenshots/2016-09-03_00h53_21.png -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## What changed? 2 | 3 | _Describe the changes you have made to improve this project._ 4 | 5 | _Closed issues._ 6 | -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "9.0.100", 4 | "rollForward": "latestFeature", 5 | "allowPrerelease": false 6 | } 7 | } -------------------------------------------------------------------------------- /src/GongSolutions.WPF.DragDrop/Icons/EffectCopy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/punker76/gong-wpf-dragdrop/HEAD/src/GongSolutions.WPF.DragDrop/Icons/EffectCopy.png -------------------------------------------------------------------------------- /src/GongSolutions.WPF.DragDrop/Icons/EffectLink.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/punker76/gong-wpf-dragdrop/HEAD/src/GongSolutions.WPF.DragDrop/Icons/EffectLink.png -------------------------------------------------------------------------------- /src/GongSolutions.WPF.DragDrop/Icons/EffectMove.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/punker76/gong-wpf-dragdrop/HEAD/src/GongSolutions.WPF.DragDrop/Icons/EffectMove.png -------------------------------------------------------------------------------- /src/GongSolutions.WPF.DragDrop/Icons/EffectNone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/punker76/gong-wpf-dragdrop/HEAD/src/GongSolutions.WPF.DragDrop/Icons/EffectNone.png -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [punker76] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | -------------------------------------------------------------------------------- /.config/dotnet-tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "isRoot": true, 4 | "tools": { 5 | "cake.tool": { 6 | "version": "5.0.0", 7 | "commands": [ 8 | "dotnet-cake" 9 | ] 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /src/GongSolutions.WPF.DragDrop/EventType.cs: -------------------------------------------------------------------------------- 1 | namespace GongSolutions.Wpf.DragDrop 2 | { 3 | public enum EventType 4 | { 5 | Auto, 6 | Tunneled, 7 | Bubbled, 8 | TunneledBubbled 9 | } 10 | } -------------------------------------------------------------------------------- /src/Showcase/FodyWeavers.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/Showcase/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | 3 | namespace Showcase.WPF.DragDrop 4 | { 5 | /// 6 | /// Interaction logic for App.xaml 7 | /// 8 | public partial class App : Application 9 | { 10 | } 11 | } -------------------------------------------------------------------------------- /src/Showcase/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | // Setting ComVisible to false makes the types in this assembly not visible 4 | // to COM components. If you need to access a type in this assembly from 5 | // COM, set the ComVisible attribute to true on that type. 6 | [assembly: ComVisible(false)] 7 | -------------------------------------------------------------------------------- /src/Showcase/Views/Issues.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Controls; 2 | 3 | namespace Showcase.WPF.DragDrop.Views 4 | { 5 | /// 6 | /// Interaction logic for Issues.xaml 7 | /// 8 | public partial class Issues : UserControl 9 | { 10 | public Issues() 11 | { 12 | this.InitializeComponent(); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /src/GongSolutions.WPF.DragDrop/ScrollingMode.cs: -------------------------------------------------------------------------------- 1 | namespace GongSolutions.Wpf.DragDrop 2 | { 3 | /// 4 | /// Specifies how reacts to drop operation. 5 | /// 6 | public enum ScrollingMode 7 | { 8 | None, 9 | HorizontalOnly, 10 | VerticalOnly, 11 | Both 12 | } 13 | } -------------------------------------------------------------------------------- /src/Showcase/Models/DataGridRowModel.cs: -------------------------------------------------------------------------------- 1 | using Faker; 2 | 3 | namespace Showcase.WPF.DragDrop.Models 4 | { 5 | public class DataGridRowModel 6 | { 7 | public string Name { get; set; } = Faker.Name.FullName(NameFormats.Standard); 8 | 9 | public string StreetName { get; set; } = Address.StreetName(); 10 | 11 | public string City { get; set; } = Address.City(); 12 | } 13 | } -------------------------------------------------------------------------------- /src/Showcase/Views/ListBoxSamples.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Controls; 2 | 3 | namespace Showcase.WPF.DragDrop.Views 4 | { 5 | /// 6 | /// Interaction logic for ListBoxSample.xaml 7 | /// 8 | public partial class ListBoxSamples : UserControl 9 | { 10 | public ListBoxSamples() 11 | { 12 | this.InitializeComponent(); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /src/Showcase/Views/ListViewSamples.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Controls; 2 | 3 | namespace Showcase.WPF.DragDrop.Views 4 | { 5 | /// 6 | /// Interaction logic for ListViewSample.xaml 7 | /// 8 | public partial class ListViewSamples : UserControl 9 | { 10 | public ListViewSamples() 11 | { 12 | this.InitializeComponent(); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /src/Showcase/Views/DataGridSamples.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Controls; 2 | 3 | namespace Showcase.WPF.DragDrop.Views 4 | { 5 | /// 6 | /// Interaction logic for DataGridSamples.xaml 7 | /// 8 | public partial class DataGridSamples : UserControl 9 | { 10 | public DataGridSamples() 11 | { 12 | this.InitializeComponent(); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /src/Showcase/Views/TabControlSamples.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Controls; 2 | 3 | namespace Showcase.WPF.DragDrop.Views 4 | { 5 | /// 6 | /// Interaction logic for TabControlSamples.xaml 7 | /// 8 | public partial class TabControlSamples : UserControl 9 | { 10 | public TabControlSamples() 11 | { 12 | this.InitializeComponent(); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /src/Showcase/Models/TabItemModel.cs: -------------------------------------------------------------------------------- 1 | namespace Showcase.WPF.DragDrop.Models 2 | { 3 | public class TabItemModel 4 | { 5 | public TabItemModel(int itemIndex) 6 | { 7 | this.Header = $"TabItem {itemIndex}"; 8 | this.Content = Faker.Lorem.Paragraph(); 9 | } 10 | 11 | public string Header { get; set; } 12 | 13 | public string Content { get; set; } 14 | } 15 | } -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | ; Top-most http://editorconfig.org/ file 2 | root = true 3 | 4 | [*] 5 | end_of_line = CRLF 6 | 7 | ; 4-column tab indentation 8 | [*.{cs,csproj,xaml,xml,props,targets}] 9 | indent_style = space 10 | indent_size = 4 11 | 12 | [*.{md,yml,json,cake}] 13 | indent_style = space 14 | indent_size = 2 15 | 16 | 17 | [*.cs] 18 | # WPF0011: Containing type should be used as registered owner. 19 | dotnet_diagnostic.WPF0011.severity = error 20 | -------------------------------------------------------------------------------- /cake.config: -------------------------------------------------------------------------------- 1 | ; This is the default configuration file for Cake. 2 | ; This file was downloaded from https://github.com/cake-build/resources 3 | 4 | [Nuget] 5 | Source=https://api.nuget.org/v3/index.json 6 | UseInProcessClient=true 7 | LoadDependencies=false 8 | 9 | [Paths] 10 | Tools=./tools 11 | Addins=./tools/Addins 12 | Modules=./tools/Modules 13 | 14 | [Settings] 15 | SkipVerification=false 16 | SkipPackageVersionCheck=true 17 | ShowProcessCommandLine=true 18 | -------------------------------------------------------------------------------- /src/Showcase/Models/FilesDropHandler.cs: -------------------------------------------------------------------------------- 1 | namespace Showcase.WPF.DragDrop.Models; 2 | 3 | using GongSolutions.Wpf.DragDrop; 4 | using MahApps.Metro.IconPacks; 5 | 6 | public class FilesDropHandler : DefaultDropHandler 7 | { 8 | public override void DragOver(IDropInfo dropInfo) 9 | { 10 | if (dropInfo is DropInfo { TargetItem: not TreeNode { Icon: PackIconMaterialKind.Folder } } typedDropInfo) 11 | typedDropInfo.AcceptChildItem = false; 12 | 13 | base.DragOver(dropInfo); 14 | } 15 | } -------------------------------------------------------------------------------- /src/GongSolutions.WPF.DragDrop/IDragItemSource.cs: -------------------------------------------------------------------------------- 1 | namespace GongSolutions.Wpf.DragDrop 2 | { 3 | /// 4 | /// Supports methods for models which can be dropped. 5 | /// 6 | public interface IDragItemSource 7 | { 8 | /// 9 | /// Indicates that the item is dropped on the destination list. 10 | /// 11 | /// Object which contains several drop information. 12 | void ItemDropped(IDropInfo dropInfo); 13 | } 14 | } -------------------------------------------------------------------------------- /src/GongSolutions.WPF.DragDrop/GongSolutions.WPF.DragDrop.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | GongSolutions.WPF.DragDrop 6 | gong-wpf-dragdrop 7 | GongSolutions.Wpf.DragDrop 8 | true 9 | Library 10 | 11 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "nuget" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "monthly" 12 | open-pull-requests-limit: 10 13 | -------------------------------------------------------------------------------- /src/GongSolutions.WPF.DragDrop/Utilities/IRootElementFinder.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | 3 | namespace GongSolutions.Wpf.DragDrop.Utilities 4 | { 5 | /// 6 | /// Interface implemented by the root element finder. 7 | /// 8 | public interface IRootElementFinder 9 | { 10 | /// 11 | /// Gets the root element. 12 | /// 13 | /// The visual element to find the root for. 14 | /// The root element. 15 | UIElement FindRoot(DependencyObject visual); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /GitVersion.yml: -------------------------------------------------------------------------------- 1 | assembly-versioning-scheme: Major 2 | assembly-file-versioning-scheme: MajorMinorPatchTag 3 | next-version: 4.0.0 4 | mode: ContinuousDeployment 5 | branches: 6 | master: 7 | regex: ^main 8 | mode: ContinuousDeployment 9 | tag: rc 10 | prevent-increment-of-merged-branch-version: true 11 | track-merge-target: false 12 | is-release-branch: true 13 | develop: 14 | mode: ContinuousDeployment 15 | tag: alpha 16 | prevent-increment-of-merged-branch-version: true 17 | track-merge-target: true 18 | pull-request: 19 | mode: ContinuousDelivery 20 | ignore: 21 | sha: [] 22 | -------------------------------------------------------------------------------- /src/Showcase/ViewModels/ViewModelBase.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Runtime.CompilerServices; 3 | using JetBrains.Annotations; 4 | 5 | namespace Showcase.WPF.DragDrop.ViewModels 6 | { 7 | public class ViewModelBase : INotifyPropertyChanged 8 | { 9 | public event PropertyChangedEventHandler PropertyChanged; 10 | 11 | [NotifyPropertyChangedInvocator] 12 | protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) 13 | { 14 | this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /src/Showcase/Models/DragAdornerTemplateSelector.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Controls; 3 | 4 | namespace Showcase.WPF.DragDrop.Models 5 | { 6 | public class DragAdornerTemplateSelector : DataTemplateSelector 7 | { 8 | public DataTemplate TemplateEven { get; set; } 9 | 10 | public DataTemplate TemplateOdd { get; set; } 11 | 12 | public override DataTemplate SelectTemplate(object item, DependencyObject container) 13 | { 14 | var itemModel = item as ItemModel; 15 | return itemModel != null && (itemModel.Index & 0x01) == 0 ? this.TemplateEven : this.TemplateOdd; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/GongSolutions.WPF.DragDrop/IDragPreviewItemsSorter.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | 3 | namespace GongSolutions.Wpf.DragDrop 4 | { 5 | /// 6 | /// Interface for objects that sort an IEnumerable of drag preview items 7 | /// 8 | public interface IDragPreviewItemsSorter 9 | { 10 | /// 11 | /// Sort the IEnumerable of items that are being shown in a drag preview 12 | /// 13 | /// Enumerable of dragged items to sort 14 | /// The sorted list of dragged items 15 | IEnumerable SortDragPreviewItems(IEnumerable items); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/GongSolutions.WPF.DragDrop/ICloneableDragItem.cs: -------------------------------------------------------------------------------- 1 | namespace GongSolutions.Wpf.DragDrop 2 | { 3 | /// 4 | /// Supports cloning like the ICloneable interface, which creates a new instance of a class with the same value as an existing instance. 5 | /// 6 | public interface ICloneableDragItem 7 | { 8 | /// 9 | /// Creates a new object that is a copy of the current instance. 10 | /// 11 | /// Object which contains several drop information. 12 | /// A new object that is a copy of this instance. 13 | object CloneItem(IDropInfo dropInfo); 14 | } 15 | } -------------------------------------------------------------------------------- /src/GongSolutions.WPF.DragDrop/IDropTargetItemsSorter.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | 3 | namespace GongSolutions.Wpf.DragDrop 4 | { 5 | /// 6 | /// Interface for objects that sort an IEnumerable of drag drop items that are 7 | /// going to be dropped on some target 8 | /// 9 | public interface IDropTargetItemsSorter 10 | { 11 | /// 12 | /// Sort the IEnumerable of items that are going to be dropped on a target 13 | /// 14 | /// Enumerable of dragged items to sort 15 | /// The sorted list of dragged items 16 | IEnumerable SortDropTargetItems(IEnumerable items); 17 | } 18 | } -------------------------------------------------------------------------------- /src/Showcase/CustomControls/CustomListBox.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Controls; 3 | 4 | namespace Showcase.WPF.DragDrop.CustomControls 5 | { 6 | public class CustomListBox : ListBox 7 | { 8 | protected override DependencyObject GetContainerForItemOverride() 9 | { 10 | return new CustomListBoxItem(); 11 | } 12 | 13 | protected override bool IsItemItsOwnContainerOverride(object item) 14 | { 15 | return item is CustomListBoxItem; 16 | } 17 | } 18 | 19 | public class CustomListBoxItem : ListBoxItem 20 | { 21 | public override string ToString() 22 | { 23 | return base.ToString(); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /src/GongSolutions.WPF.DragDrop/DropHintState.cs: -------------------------------------------------------------------------------- 1 | namespace GongSolutions.Wpf.DragDrop 2 | { 3 | /// 4 | /// Represents the mode of the drop hint to display different adorner based on the state of the hint. 5 | /// 6 | public enum DropHintState 7 | { 8 | /// 9 | /// Default hint state, indicating that a drop target is available for drop. 10 | /// 11 | None, 12 | /// 13 | /// Highlights the target, such as on drag over. 14 | /// 15 | Active, 16 | /// 17 | /// Warning state, indicating that the drop target is not available for drop. 18 | /// 19 | Error 20 | } 21 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: Bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Version [e.g. 22] 29 | 30 | **Additional context** 31 | Add any other context about the problem here. 32 | -------------------------------------------------------------------------------- /src/GongSolutions.WPF.DragDrop/DropTargetAdorners.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace GongSolutions.Wpf.DragDrop 4 | { 5 | public class DropTargetAdorners 6 | { 7 | /// 8 | /// Gets the type of the default highlight target adorner. 9 | /// 10 | public static Type Highlight { get; } = typeof(DropTargetHighlightAdorner); 11 | 12 | /// 13 | /// Gets the type of the default insert target adorner. 14 | /// 15 | public static Type Insert { get; } = typeof(DropTargetInsertionAdorner); 16 | 17 | /// 18 | /// Get the type for the default hint target adorner. 19 | /// 20 | public static Type Hint { get; } = typeof(DropTargetHintAdorner); 21 | } 22 | } -------------------------------------------------------------------------------- /src/GongSolutions.WPF.DragDrop/DragDropEffectPreview.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | 3 | namespace GongSolutions.Wpf.DragDrop 4 | { 5 | internal class DragDropEffectPreview : DragDropPreview 6 | { 7 | public DragDropEffectPreview(UIElement rootElement, UIElement previewElement, Point translation, DragDropEffects effects, string effectText, string destinationText) 8 | : base(rootElement, previewElement, translation, default) 9 | { 10 | this.Effects = effects; 11 | this.EffectText = effectText; 12 | this.DestinationText = destinationText; 13 | } 14 | 15 | public DragDropEffects Effects { get; set; } 16 | 17 | public string EffectText { get; set; } 18 | 19 | public string DestinationText { get; set; } 20 | } 21 | } -------------------------------------------------------------------------------- /NuGet.Config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/GongSolutions.WPF.DragDrop/DropHintInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace GongSolutions.Wpf.DragDrop 4 | { 5 | /// 6 | /// Implementation of the interface to hold DropHint information. 7 | /// 8 | public class DropHintInfo : IDropHintInfo 9 | { 10 | /// 11 | public IDragInfo DragInfo { get; } 12 | 13 | /// 14 | public Type DropTargetHintAdorner { get; set; } 15 | 16 | /// 17 | public string DropHintText { get; set; } 18 | 19 | /// 20 | public DropHintState DropTargetHintState { get; set; } 21 | 22 | public DropHintInfo(IDragInfo dragInfo) 23 | { 24 | this.DragInfo = dragInfo; 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/GongSolutions.WPF.DragDrop/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using System.Windows.Markup; 4 | 5 | [assembly: CLSCompliant(true)] 6 | 7 | [assembly: XmlnsPrefix("urn:gong-wpf-dragdrop", "dd")] 8 | [assembly: XmlnsDefinition("urn:gong-wpf-dragdrop", "GongSolutions.Wpf.DragDrop")] 9 | [assembly: XmlnsDefinition("urn:gong-wpf-dragdrop", "GongSolutions.Wpf.DragDrop.Utilities")] 10 | // Setting ComVisible to false makes the types in this assembly not visible 11 | // to COM components. If you need to access a type in this assembly from 12 | // COM, set the ComVisible attribute to true on that type. 13 | [assembly: ComVisible(false)] 14 | // The following GUID is for the ID of the typelib if this project is exposed to COM 15 | [assembly: Guid("940084f7-d48e-41b3-9e0d-cf574d587643")] -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # These files are text and should be normalized (convert crlf => lf) 5 | # Custom for Visual Studio 6 | *.cs diff=csharp 7 | *.xaml merge=union 8 | *.sln merge=union 9 | *.csproj merge=union 10 | *.vbproj merge=union 11 | *.fsproj merge=union 12 | *.dbproj merge=union 13 | 14 | # Standard to msysgit 15 | *.doc diff=astextplain 16 | *.DOC diff=astextplain 17 | *.docx diff=astextplain 18 | *.DOCX diff=astextplain 19 | *.dot diff=astextplain 20 | *.DOT diff=astextplain 21 | *.pdf diff=astextplain 22 | *.PDF diff=astextplain 23 | *.rtf diff=astextplain 24 | *.RTF diff=astextplain 25 | 26 | # Images should be treated as binary 27 | # (binary is a macro for -text -diff) 28 | *.png binary 29 | *.jepg binary 30 | *.jpg binary 31 | 32 | *.sdf binary -------------------------------------------------------------------------------- /src/Showcase/MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Windows.Controls; 4 | using System.Windows; 5 | using Showcase.WPF.DragDrop.ViewModels; 6 | 7 | namespace Showcase.WPF.DragDrop 8 | { 9 | /// 10 | /// Interaction logic for MainWindow.xaml 11 | /// 12 | public partial class MainWindow : Window 13 | { 14 | public MainWindow() 15 | { 16 | this.InitializeComponent(); 17 | this.DataContext = new MainViewModel(); 18 | this.Loaded += this.MainWindowLoaded; 19 | } 20 | 21 | private void MainWindowLoaded(object sender, RoutedEventArgs e) 22 | { 23 | var appArgs = Environment.GetCommandLineArgs(); 24 | if (appArgs.Length > 1 && appArgs[1] == "anotherOne") 25 | { 26 | this.MainTabControl.SelectedItem = this.MainTabControl.Items.OfType().FirstOrDefault(t => (string)t.Header == "Mixed"); 27 | } 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /src/GongSolutions.WPF.DragDrop/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | true 7 | 8 | true 9 | 10 | 11 | true 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/Showcase/Models/ClonableItemModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Showcase.WPF.DragDrop.Models 4 | { 5 | public class ClonableItemModel : ItemModel, ICloneable 6 | { 7 | public ClonableItemModel() 8 | { 9 | } 10 | 11 | public ClonableItemModel(int itemIndex) 12 | : base(itemIndex) 13 | { 14 | } 15 | 16 | public object Clone() 17 | { 18 | var clonableItemModel = new ClonableItemModel(); 19 | clonableItemModel.BindableDoubleValue = this.BindableDoubleValue; 20 | clonableItemModel.SubItemCollection.Clear(); 21 | foreach (var subItem in this.SubItemCollection) 22 | { 23 | clonableItemModel.SubItemCollection.Add(subItem); 24 | } 25 | clonableItemModel.SelectedSubItem = this.SelectedSubItem; 26 | clonableItemModel.Index = this.Index; 27 | clonableItemModel.Caption = $"Cloned Item {this.Index}"; 28 | return clonableItemModel; 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src/GongSolutions.WPF.DragDrop/IDropInfoBuilder.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using JetBrains.Annotations; 3 | 4 | namespace GongSolutions.Wpf.DragDrop 5 | { 6 | /// 7 | /// Interface implemented by Drop Info Builders. 8 | /// It enables custom construction of IDropInfo objects to support 3rd party controls like DevExpress, Telerik, etc. 9 | /// 10 | public interface IDropInfoBuilder 11 | { 12 | /// 13 | /// Initializes a new instance of the DropInfo class. 14 | /// 15 | /// The sender of the drop event. 16 | /// The drag event arguments. 17 | /// Information about the drag source, if the drag came from within the framework. 18 | /// The type of the underlying event (tunneled or bubbled). 19 | [CanBeNull] 20 | IDropInfo CreateDropInfo(object sender, DragEventArgs e, [CanBeNull] IDragInfo dragInfo, EventType eventType); 21 | } 22 | } -------------------------------------------------------------------------------- /GitReleaseManager.yaml: -------------------------------------------------------------------------------- 1 | create: 2 | include-footer: true 3 | footer-heading: Where to get it 4 | footer-content: You can download this release from [gong-wpf-dragdrop](https://github.com/punker76/gong-wpf-dragdrop/releases/{milestone}) 5 | footer-includes-milestone: true 6 | milestone-replace-text: '{milestone}' 7 | export: 8 | include-created-date-in-title: true 9 | created-date-string-format: MMMM dd, yyyy 10 | perform-regex-removal: true 11 | regex-text: '### Where to get it(\r\n)*You can .*\)' 12 | multiline-regex: true 13 | issue-labels-include: 14 | - Breaking Change 15 | - Bug 16 | - Bug Fix 17 | - Feature 18 | - Feature Request 19 | - Improvement 20 | - Enhancement 21 | - Hacktoberfest 22 | issue-labels-exclude: 23 | - Internal Refactoring 24 | - Build 25 | - Question 26 | - WontFix 27 | - Duplicate 28 | - Housekeeping 29 | - Documentation 30 | issue-labels-alias: 31 | - name: Documentation 32 | header: Documentation 33 | plural: Documentation 34 | - name: Hacktoberfest 35 | header: Hacktoberfest 36 | plural: Hacktoberfest -------------------------------------------------------------------------------- /src/Showcase/Models/ListBoxCustomDropHandler.cs: -------------------------------------------------------------------------------- 1 | using GongSolutions.Wpf.DragDrop; 2 | 3 | namespace Showcase.WPF.DragDrop.Models 4 | { 5 | public class ListBoxCustomDropHandler : DefaultDropHandler 6 | { 7 | /// 8 | public override void DragOver(IDropInfo dropInfo) 9 | { 10 | if (dropInfo.VisualTarget == dropInfo.DragInfo.VisualSource) 11 | { 12 | dropInfo.NotHandled = dropInfo.VisualTarget == dropInfo.DragInfo.VisualSource; 13 | } 14 | else 15 | { 16 | base.DragOver(dropInfo); 17 | } 18 | } 19 | 20 | /// 21 | public override void Drop(IDropInfo dropInfo) 22 | { 23 | if (dropInfo.VisualTarget == dropInfo.DragInfo.VisualSource) 24 | { 25 | dropInfo.NotHandled = dropInfo.VisualTarget == dropInfo.DragInfo.VisualSource; 26 | } 27 | else 28 | { 29 | base.Drop(dropInfo); 30 | } 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/Showcase/ViewModels/SimpleCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Input; 3 | 4 | namespace Showcase.WPF.DragDrop.ViewModels 5 | { 6 | public class SimpleCommand : ICommand 7 | { 8 | public SimpleCommand(Action execute = null, Predicate canExecute = null) 9 | { 10 | this.CanExecuteDelegate = canExecute; 11 | this.ExecuteDelegate = execute; 12 | } 13 | 14 | public Predicate CanExecuteDelegate { get; set; } 15 | 16 | public Action ExecuteDelegate { get; set; } 17 | 18 | public bool CanExecute(object parameter) 19 | { 20 | var canExecute = this.CanExecuteDelegate; 21 | return canExecute == null || canExecute(parameter); 22 | } 23 | 24 | public event EventHandler CanExecuteChanged 25 | { 26 | add => CommandManager.RequerySuggested += value; 27 | remove => CommandManager.RequerySuggested -= value; 28 | } 29 | 30 | public void Execute(object parameter) 31 | { 32 | this.ExecuteDelegate?.Invoke(parameter); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | // Use IntelliSense to find out which attributes exist for C# debugging 6 | // Use hover for the description of the existing attributes 7 | // For further information visit https://github.com/dotnet/vscode-csharp/blob/main/debugger-launchjson.md 8 | "name": ".NET Core Launch (console)", 9 | "type": "coreclr", 10 | "request": "launch", 11 | "preLaunchTask": "build", 12 | // If you have changed target frameworks, make sure to update the program path. 13 | "program": "${workspaceFolder}/src/Showcase/bin/Debug/net6.0-windows/Showcase.WPF.DragDrop.dll", 14 | "args": [], 15 | "cwd": "${workspaceFolder}/src/Showcase", 16 | // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console 17 | "console": "internalConsole", 18 | "stopAtEntry": false 19 | }, 20 | { 21 | "name": ".NET Core Attach", 22 | "type": "coreclr", 23 | "request": "attach" 24 | } 25 | ] 26 | } -------------------------------------------------------------------------------- /src/GongSolutions.WPF.DragDrop/IDragInfoBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows; 3 | using System.Windows.Input; 4 | using JetBrains.Annotations; 5 | 6 | namespace GongSolutions.Wpf.DragDrop 7 | { 8 | /// 9 | /// Interface implemented by Drag Info Builders. 10 | /// It enables custom construction of DragInfo objects to support 3rd party controls like DevExpress, Telerik, etc. 11 | /// 12 | public interface IDragInfoBuilder 13 | { 14 | /// 15 | /// Initializes a new instance of the DragInfo class. 16 | /// 17 | /// The sender of the input event that initiated the drag operation. 18 | /// The original source of the input event. 19 | /// The mouse button which was used for the drag operation. 20 | /// A function of the input event which is used to get drag position points. 21 | [CanBeNull] 22 | IDragInfo CreateDragInfo(object sender, object originalSource, MouseButton mouseButton, Func getPosition); 23 | } 24 | } -------------------------------------------------------------------------------- /src/Directory.build.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | GongSolutions.WPF.DragDrop 6 | GongSolutions.WPF.DragDrop 7 | Copyright © 2013 - $([System.DateTime]::Today.ToString(yyyy)) GongSolutions.WPF.DragDrop 8 | An easy to use drag'n'drop framework for WPF applications. 9 | 10 | true 11 | 4.0.0.0 12 | 4.0.0.0 13 | 4.0.0.0 14 | 4.0.0.0 15 | 16 | 17 | 18 | $([System.IO.Path]::Combine('$(IntermediateOutputPath)','$(TargetFrameworkMoniker).AssemblyAttributes$(DefaultLanguageSourceExtension)')) 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/Showcase/Views/MixedSamples.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Windows; 6 | using System.Windows.Controls; 7 | 8 | namespace Showcase.WPF.DragDrop.Views 9 | { 10 | /// 11 | /// Interaction logic for MixedSamples.xaml 12 | /// 13 | public partial class MixedSamples : UserControl 14 | { 15 | public MixedSamples() 16 | { 17 | this.InitializeComponent(); 18 | this.Loaded += this.MainWindowLoaded; 19 | } 20 | 21 | private void MainWindowLoaded(object sender, RoutedEventArgs e) 22 | { 23 | var appArgs = Environment.GetCommandLineArgs(); 24 | if (appArgs.Length > 1 && appArgs[1] == "anotherOne") 25 | { 26 | this.MixedTabControl.SelectedItem = this.MixedTabControl.Items.OfType().FirstOrDefault(t => (string)t.Header == "Outside"); 27 | } 28 | } 29 | 30 | private void ButtonOpenAnotherAppOnClick(object sender, RoutedEventArgs e) 31 | { 32 | Process.Start(Assembly.GetEntryAssembly().Location, "anotherOne"); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | 2 | name: ci 3 | 4 | on: 5 | push: 6 | branches: 7 | - main 8 | - develop 9 | pull_request: 10 | branches: 11 | - develop 12 | 13 | jobs: 14 | windows-latest: 15 | name: windows-latest 16 | runs-on: windows-latest 17 | steps: 18 | - uses: actions/checkout@v1 19 | - name: Setup .NET 20 | uses: actions/setup-dotnet@v1 21 | with: 22 | dotnet-version: | 23 | 6.x 24 | 8.x 25 | 9.x 26 | - name: List dotnet sdks 27 | run: dotnet --info 28 | - name: Run the Cake script 29 | uses: cake-build/cake-action@v1 30 | with: 31 | cake-version: tool-manifest 32 | verbosity: Normal 33 | script-path: build.cake 34 | target: ci 35 | env: 36 | azure-key-vault-url: ${{ secrets.AZURE_KEY_VAULT_URL }} 37 | azure-key-vault-client-id: ${{ secrets.AZURE_KEY_VAULT_CLIENT_ID }} 38 | azure-key-vault-tenant-id: ${{ secrets.AZURE_KEY_VAULT_TENANT_ID }} 39 | azure-key-vault-client-secret: ${{ secrets.AZURE_KEY_VAULT_CLIENT_SECRET }} 40 | azure-key-vault-certificate: ${{ secrets.AZURE_KEY_VAULT_CERTIFICATE }} 41 | -------------------------------------------------------------------------------- /src/Showcase/Views/TreeViewSamples.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Controls; 2 | using GongSolutions.Wpf.DragDrop.Utilities; 3 | 4 | namespace Showcase.WPF.DragDrop.Views 5 | { 6 | /// 7 | /// Interaction logic for TreeViewSamples.xaml 8 | /// 9 | public partial class TreeViewSamples : UserControl 10 | { 11 | public TreeViewSamples() 12 | { 13 | this.InitializeComponent(); 14 | } 15 | 16 | private void LeftBoundTreeView_RequestBringIntoView(object sender, System.Windows.RequestBringIntoViewEventArgs e) 17 | { 18 | e.Handled = true; 19 | } 20 | 21 | private void LeftBoundTreeView_Loaded(object sender, System.Windows.RoutedEventArgs e) 22 | { 23 | // Prevent automatic horizontal and vertical scrolling by subscribing to ScrollContentPresenter's RequestBringIntoView event and flag it as handled. 24 | var p = (sender as TreeView).GetVisualDescendent(); 25 | if (p != null) 26 | { 27 | p.RequestBringIntoView -= this.LeftBoundTreeView_RequestBringIntoView; 28 | p.RequestBringIntoView += this.LeftBoundTreeView_RequestBringIntoView; 29 | } 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /src/Showcase/Models/NestedDropHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows; 3 | using GongSolutions.Wpf.DragDrop; 4 | 5 | namespace Showcase.WPF.DragDrop.Models 6 | { 7 | public class NestedDropHandler : IDropTarget 8 | { 9 | #if !NETCOREAPP3_1_OR_GREATER 10 | /// 11 | public void DragEnter(IDropInfo dropInfo) 12 | { 13 | // nothing here 14 | } 15 | 16 | /// 17 | public void DropHint(IDropHintInfo dropHintInfo) 18 | { 19 | // nothing here 20 | } 21 | #endif 22 | 23 | /// 24 | public void DragOver(IDropInfo dropInfo) 25 | { 26 | if (dropInfo.TargetItem?.ToString().StartsWith("Root", StringComparison.OrdinalIgnoreCase) == true) 27 | { 28 | dropInfo.Effects = DragDropEffects.Move; 29 | dropInfo.DropTargetAdorner = DropTargetAdorners.Highlight; 30 | } 31 | } 32 | 33 | #if !NETCOREAPP3_1_OR_GREATER 34 | /// 35 | public void DragLeave(IDropInfo dropInfo) 36 | { 37 | // nothing here 38 | } 39 | #endif 40 | 41 | /// 42 | public void Drop(IDropInfo dropInfo) 43 | { 44 | // nothing 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "build", 6 | "command": "dotnet", 7 | "type": "process", 8 | "args": [ 9 | "build", 10 | "${workspaceFolder}/src/GongSolutions.WPF.DragDrop.sln", 11 | "/property:GenerateFullPaths=true", 12 | "/consoleloggerparameters:NoSummary" 13 | ], 14 | "problemMatcher": "$msCompile" 15 | }, 16 | { 17 | "label": "publish", 18 | "command": "dotnet", 19 | "type": "process", 20 | "args": [ 21 | "publish", 22 | "${workspaceFolder}/src/GongSolutions.WPF.DragDrop.sln", 23 | "/property:GenerateFullPaths=true", 24 | "/consoleloggerparameters:NoSummary" 25 | ], 26 | "problemMatcher": "$msCompile" 27 | }, 28 | { 29 | "label": "watch", 30 | "command": "dotnet", 31 | "type": "process", 32 | "args": [ 33 | "watch", 34 | "run", 35 | "--project", 36 | "${workspaceFolder}/src/GongSolutions.WPF.DragDrop.sln" 37 | ], 38 | "problemMatcher": "$msCompile" 39 | } 40 | ] 41 | } -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # http://www.appveyor.com/docs/appveyor-yml 2 | 3 | branches: 4 | only: 5 | - develop 6 | - main 7 | 8 | environment: 9 | # bad, but without this, gitversion doesn't work anymore 10 | IGNORE_NORMALISATION_GIT_HEAD_MOVE: 1 11 | azure-key-vault-url: 12 | secure: 1mKS/HfCVq+iYNRVSrrN8NEowOkKt3knrpMzw+SOy3g= 13 | azure-key-vault-client-id: 14 | secure: JfSqzmsJdXB6uIxttCRoQw1NygwxqXHDj9uIqQnWOb9VCnQYlRPlAnxgW0yTSX4b 15 | azure-key-vault-tenant-id: 16 | secure: FxjkcqtpulfpDpfSAu4onaLVP/H1S1ORRCQCqsZkDC6YhCSmFoMxYNsWv5uGe3ah 17 | azure-key-vault-client-secret: 18 | secure: CUpRJxMLeUZwNPMcqI0wECaWfy5AMnWn1UZhBd9WnQ3Z16lJP1Vzrkf24mccbhUD 19 | azure-key-vault-certificate: 20 | secure: BSPdW2TgnQtoQXXbeDECug== 21 | 22 | image: Visual Studio 2022 23 | test: false 24 | 25 | # install: 26 | # - ps: Invoke-WebRequest 'https://dot.net/v1/dotnet-install.ps1' -OutFile 'dotnet-install.ps1' 27 | # - ps: ./dotnet-install.ps1 -Version 8.0.403 -InstallDir "C:\Program Files\dotnet" 28 | 29 | pull_requests: 30 | do_not_increment_build_number: false 31 | 32 | build_script: 33 | - ps: dotnet --info 34 | - ps: gitversion /version 35 | - ps: .\build.ps1 --target=ci --verbosity=diagnostic 36 | 37 | artifacts: 38 | - path: \Publish\*.* 39 | 40 | nuget: 41 | disable_publish_on_pr: true 42 | 43 | skip_commits: 44 | files: 45 | - '**/*.md' 46 | -------------------------------------------------------------------------------- /src/GongSolutions.WPF.DragDrop/Utilities/RootElementFinder.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Controls; 3 | 4 | namespace GongSolutions.Wpf.DragDrop.Utilities 5 | { 6 | public class RootElementFinder : IRootElementFinder 7 | { 8 | public UIElement FindRoot(DependencyObject visual) 9 | { 10 | var parentWindow = Window.GetWindow(visual); 11 | var rootElement = parentWindow != null ? parentWindow.Content as UIElement : null; 12 | if (rootElement == null) 13 | { 14 | if (Application.Current != null && Application.Current.MainWindow != null) 15 | { 16 | rootElement = Application.Current.MainWindow.Content as UIElement; 17 | } 18 | if (rootElement == null) 19 | { 20 | rootElement = visual.GetVisualAncestor() ?? visual.GetVisualAncestor() as UIElement; 21 | } 22 | } 23 | 24 | // i don't want the fu... windows forms reference 25 | // if (rootElement == null) { 26 | // var elementHost = m_DragInfo.VisualSource.GetVisualAncestor(); 27 | // rootElement = elementHost != null ? elementHost.Child : null; 28 | // } 29 | return rootElement; 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /src/Directory.packages.props: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | true 11 | 12 | true 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/GongSolutions.WPF.DragDrop/Utilities/TreeViewItemExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Controls; 3 | 4 | namespace GongSolutions.Wpf.DragDrop.Utilities 5 | { 6 | /// 7 | /// Extension methods for TreeViewItem 8 | /// 9 | public static class TreeViewItemExtensions 10 | { 11 | /// 12 | /// Try get the height of the header part for the given TreeViewItem. 13 | /// If there is no PART_Header it will return Size.Empty. 14 | /// 15 | /// The TreeViewItem. 16 | public static Size GetHeaderSize(this TreeViewItem item) 17 | { 18 | if (item == null) 19 | { 20 | return Size.Empty; 21 | } 22 | var header = GetHeaderControl(item); 23 | return header != null ? new Size(header.ActualWidth, header.ActualHeight) : item.RenderSize; 24 | } 25 | 26 | /// 27 | /// Try get the header part of the given TreeViewItem. 28 | /// If there is no PART_Header it will return null. 29 | /// 30 | /// The TreeViewItem. 31 | public static FrameworkElement GetHeaderControl(this TreeViewItem item) 32 | { 33 | return item?.Template?.FindName("PART_Header", item) as FrameworkElement; 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /NOTICE.md: -------------------------------------------------------------------------------- 1 | This license applies to modified Microsoft WPF code used in GongSolutions.WPF.DragDrop/Utilities/VisualTreeDescendantBoundsHelper.cs and originally sourced from https://github.com/dotnet/wpf/blob/83b9af142acd341d4bf470450e8b5c3ec3723d76/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Visual.cs 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) .NET Foundation and Contributors 6 | 7 | All rights reserved. 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in all 17 | copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | SOFTWARE. 26 | -------------------------------------------------------------------------------- /src/GongSolutions.WPF.DragDrop/IDropHintInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace GongSolutions.Wpf.DragDrop 4 | { 5 | /// 6 | /// This interface is used with the for 7 | /// hint to the user about potential drop targets. 8 | /// 9 | public interface IDropHintInfo 10 | { 11 | /// 12 | /// Gets a object holding information about the source of the drag, 13 | /// if the drag came from within the framework. 14 | /// 15 | IDragInfo DragInfo { get; } 16 | 17 | /// 18 | /// Gets or sets the class of drop target hint to display. 19 | /// 20 | /// 21 | /// The standard drop target Adorner classes are held in the 22 | /// class. 23 | /// 24 | Type DropTargetHintAdorner { get; set; } 25 | 26 | /// 27 | /// Get or set the text that is displayed when initial drop hint is displayed. 28 | /// 29 | /// 30 | /// This corresponds to in 31 | /// and . 32 | /// 33 | string DropHintText { get; set; } 34 | 35 | /// 36 | /// The hint state to display different colors for hints. 37 | /// 38 | DropHintState DropTargetHintState { get; set; } 39 | } 40 | } -------------------------------------------------------------------------------- /src/Showcase/Models/GroupedItem.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Runtime.CompilerServices; 3 | using JetBrains.Annotations; 4 | 5 | namespace Showcase.WPF.DragDrop.Models 6 | { 7 | public class GroupedItem : INotifyPropertyChanged 8 | { 9 | private string _caption; 10 | private string _group; 11 | 12 | public GroupedItem(int group, int item) 13 | { 14 | this.Caption = $"Item {item} from Group {group}"; 15 | this._group = $"Group {group}"; 16 | } 17 | 18 | public string Caption 19 | { 20 | get => this._caption; 21 | set 22 | { 23 | if (value == this._caption) return; 24 | this._caption = value; 25 | this.OnPropertyChanged(); 26 | } 27 | } 28 | 29 | public string Group 30 | 31 | { 32 | get => this._group; 33 | set 34 | { 35 | if (value == this._group) 36 | { 37 | return; 38 | } 39 | 40 | this._group = value; 41 | this.OnPropertyChanged(); 42 | } 43 | } 44 | 45 | public event PropertyChangedEventHandler PropertyChanged; 46 | 47 | [NotifyPropertyChangedInvocator] 48 | protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) 49 | { 50 | this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # PLEASE READ BEFORE POSTING AN ISSUE 2 | 3 | This is a place for issues for GongSolutions.WPF.DragDrop itself. Questions are better asked in the [Gitter](https://gitter.im/punker76/gong-wpf-dragdrop) room. 4 | 5 | ### Seriously consider creating and linking to a test repo which takes absolutely minimal setup to illustrate how reproduce the problem. 6 | 7 | My time is limited and .Zip files, code snippets and partial examples are often a time sink. GitHub also provides great communication and code review tools which can be utilised. 8 | 9 | ## HOW TO POST A GOOD SAMPLE. 10 | 11 | Follow these guidelines and I will most likely look at the issue sooner: 12 | 13 | * Post a full GitHub repository. Not a zip file, half baked snippet etc. If GitHub is new to you consider it a great learning opportunity and chance to get involved. 14 | * The repository should have just ONE step max for me to get running, and that is "Restore NuGet Packages". If there are any other missing dependencies, or uncompiling features I will most likely move on to another issue. 15 | * I'm not trying to be awkward. I'm just busy and I'm helping a lot of people, not just you, so help me out and I will help you out. 16 | 17 | 18 | ## What steps will reproduce this issue? 19 | 20 | _Write problem description here_ 21 | 22 | ### Expected outcome 23 | 24 | _Write expected outcome here_ 25 | 26 | ### Repo 27 | 28 | _Link to the Repo_ 29 | 30 | ### Environment 31 | 32 | - GongSolutions.WPF.DragDrop __v?.?.?__ 33 | - Windows OS __??__ 34 | - Visual Studio __20xx__ 35 | - .NET Framework __?.?__ 36 | -------------------------------------------------------------------------------- /src/GongSolutions.WPF.DragDrop/DropTargetHintWeakReference.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows; 3 | 4 | namespace GongSolutions.Wpf.DragDrop 5 | { 6 | /// 7 | /// Wrapper of the so we only have weak references to the drop targets 8 | /// to avoid memory leaks. 9 | /// 10 | internal sealed class DropTargetHintWeakReference : IDisposable 11 | { 12 | private readonly WeakReference _dropTarget; 13 | private DropTargetHintAdorner dropTargetHintAdorner; 14 | 15 | public DropTargetHintWeakReference(UIElement dropTarget) 16 | { 17 | this._dropTarget = new WeakReference(dropTarget); 18 | } 19 | 20 | public UIElement Target => this._dropTarget.TryGetTarget(out var target) ? target : null; 21 | 22 | /// 23 | /// Property indicating if the weak reference is still alive, or should be disposed of. 24 | /// 25 | public bool IsAlive => this._dropTarget.TryGetTarget(out _); 26 | 27 | /// 28 | /// The current adorner for the drop target. 29 | /// 30 | public DropTargetHintAdorner DropTargetHintAdorner 31 | { 32 | get => this.dropTargetHintAdorner; 33 | set 34 | { 35 | this.dropTargetHintAdorner?.Detach(); 36 | this.dropTargetHintAdorner = value; 37 | } 38 | } 39 | 40 | public void Dispose() 41 | { 42 | this.DropTargetHintAdorner = null; 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) Jan Karger, Steven Kirk and Contributors. All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of gong-wpf-dragdrop nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /src/GongSolutions.WPF.DragDrop/Directory.build.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | True 6 | 7 | 8 | 9 | 10 | 11 | 12 | Jan Karger, Steven Kirk, mitchell.jon 13 | gong-wpf-dragdrop 14 | LICENSE 15 | https://github.com/punker76/gong-wpf-dragdrop 16 | GongSolutions.Wpf.DragDrop.png 17 | WPF;Windows;UI;XAML;Toolkit;Library;.NET 18 | https://github.com/punker76/gong-wpf-dragdrop/releases 19 | https://github.com/punker76/gong-wpf-dragdrop.git 20 | git 21 | true 22 | 23 | 24 | 25 | 26 | True 27 | $(MSBuildProjectDirectory)\..\gong.public.snk 28 | false 29 | true 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /src/Showcase/MainWindow.xaml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /src/Showcase/Showcase.WPF.DragDrop.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | net9.0-windows;net8.0-windows;net6.0-windows;net462 6 | Showcase.WPF.DragDrop 7 | Showcase.WPF.DragDrop 8 | true 9 | Showcase application for GongSolutions.WPF.DragDrop 10 | 11 | false 12 | 13 | 14 | 15 | WinExe 16 | SA1652;WPF0041 17 | app.manifest 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | all 34 | compile; runtime; build; native; contentfiles; analyzers 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/GongSolutions.WPF.DragDrop/DefaultDragHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Linq; 4 | using System.Windows; 5 | using GongSolutions.Wpf.DragDrop.Utilities; 6 | 7 | namespace GongSolutions.Wpf.DragDrop 8 | { 9 | /// 10 | /// The default drag handler for GongSolutions.Wpf.DragDrop. 11 | /// 12 | public class DefaultDragHandler : IDragSource 13 | { 14 | /// 15 | public virtual void StartDrag(IDragInfo dragInfo) 16 | { 17 | var items = TypeUtilities.CreateDynamicallyTypedList(dragInfo.SourceItems).Cast().ToList(); 18 | if (items.Count > 1) 19 | { 20 | dragInfo.Data = items; 21 | } 22 | else 23 | { 24 | // special case: if the single item is an enumerable then we can not drop it as single item 25 | var singleItem = items.FirstOrDefault(); 26 | dragInfo.Data = singleItem is IEnumerable and not string ? items : singleItem; 27 | } 28 | 29 | dragInfo.Effects = dragInfo.Data != null ? DragDropEffects.Copy | DragDropEffects.Move : DragDropEffects.None; 30 | } 31 | 32 | /// 33 | public virtual bool CanStartDrag(IDragInfo dragInfo) 34 | { 35 | return true; 36 | } 37 | 38 | /// 39 | public virtual void Dropped(IDropInfo dropInfo) 40 | { 41 | } 42 | 43 | /// 44 | public virtual void DragDropOperationFinished(DragDropEffects operationResult, IDragInfo dragInfo) 45 | { 46 | // nothing here 47 | } 48 | 49 | /// 50 | public virtual void DragCancelled() 51 | { 52 | } 53 | 54 | /// 55 | public virtual bool TryCatchOccurredException(Exception exception) 56 | { 57 | return false; 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /src/Directory.build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | false 5 | true 6 | 7 | 8 | 9 | 10 | net8.0-windows;net6.0-windows;net462 11 | true 12 | false 13 | true 14 | latest 15 | latest 16 | true 17 | Embedded 18 | $(NoWarn);CS1591 19 | $(NoError);CS1591 20 | true 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /src/GongSolutions.WPF.DragDrop/DropHintData.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Runtime.CompilerServices; 3 | using JetBrains.Annotations; 4 | 5 | namespace GongSolutions.Wpf.DragDrop 6 | { 7 | /// 8 | /// Data presented in drop hint adorner. 9 | /// 10 | public class DropHintData : INotifyPropertyChanged 11 | { 12 | private DropHintState hintState; 13 | private string hintText; 14 | 15 | public DropHintData(DropHintState hintState, string hintText) 16 | { 17 | this.HintState = hintState; 18 | this.HintText = hintText; 19 | } 20 | 21 | /// 22 | /// The hint text to display to the user. See 23 | /// and . 24 | /// 25 | public string HintText 26 | { 27 | get => this.hintText; 28 | set 29 | { 30 | if (value == this.hintText) return; 31 | this.hintText = value; 32 | this.OnPropertyChanged(); 33 | } 34 | } 35 | 36 | /// 37 | /// The hint state to display different colors for hints. See 38 | /// and . 39 | /// 40 | public DropHintState HintState 41 | { 42 | get => this.hintState; 43 | set 44 | { 45 | if (value == this.hintState) return; 46 | this.hintState = value; 47 | this.OnPropertyChanged(); 48 | } 49 | } 50 | 51 | public event PropertyChangedEventHandler PropertyChanged; 52 | 53 | [NotifyPropertyChangedInvocator] 54 | protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) 55 | { 56 | this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /src/GongSolutions.WPF.DragDrop.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.12.35514.174 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GongSolutions.WPF.DragDrop", "GongSolutions.WPF.DragDrop\GongSolutions.WPF.DragDrop.csproj", "{CB5BFDCE-284B-4B1E-A99A-ED4764D26E74}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Showcase.WPF.DragDrop", "Showcase\Showcase.WPF.DragDrop.csproj", "{4E15F482-1FE9-4614-98F7-31256B643462}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{DBB1D473-7CDE-4C02-9081-7EBC3C6C429A}" 11 | ProjectSection(SolutionItems) = preProject 12 | ..\build.cake = ..\build.cake 13 | Directory.build.props = Directory.build.props 14 | Directory.build.targets = Directory.build.targets 15 | Directory.packages.props = Directory.packages.props 16 | EndProjectSection 17 | EndProject 18 | Global 19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 20 | Debug|Any CPU = Debug|Any CPU 21 | Release|Any CPU = Release|Any CPU 22 | EndGlobalSection 23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 24 | {CB5BFDCE-284B-4B1E-A99A-ED4764D26E74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {CB5BFDCE-284B-4B1E-A99A-ED4764D26E74}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {CB5BFDCE-284B-4B1E-A99A-ED4764D26E74}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {CB5BFDCE-284B-4B1E-A99A-ED4764D26E74}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {4E15F482-1FE9-4614-98F7-31256B643462}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {4E15F482-1FE9-4614-98F7-31256B643462}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {4E15F482-1FE9-4614-98F7-31256B643462}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {4E15F482-1FE9-4614-98F7-31256B643462}.Release|Any CPU.Build.0 = Release|Any CPU 32 | EndGlobalSection 33 | GlobalSection(SolutionProperties) = preSolution 34 | HideSolutionNode = FALSE 35 | EndGlobalSection 36 | GlobalSection(ExtensibilityGlobals) = postSolution 37 | SolutionGuid = {4DA11A5C-612C-4901-AA97-FF5A87451FCA} 38 | EndGlobalSection 39 | EndGlobal 40 | -------------------------------------------------------------------------------- /Settings.XAMLStyler: -------------------------------------------------------------------------------- 1 | { 2 | "IndentSize": 4, 3 | "AttributesTolerance": 2, 4 | "KeepFirstAttributeOnSameLine": true, 5 | "MaxAttributeCharactersPerLine": 0, 6 | "MaxAttributesPerLine": 1, 7 | "NewlineExemptionElements": "RadialGradientBrush, GradientStop, LinearGradientBrush, ScaleTransform, SkewTransform, RotateTransform, TranslateTransform, Trigger, MultiTrigger, DataTrigger, MultiDataTrigger, Condition, Setter, SolidColorBrush, Pen", 8 | "SeparateByGroups": false, 9 | "AttributeIndentation": 0, 10 | "AttributeIndentationStyle": 1, 11 | "RemoveDesignTimeReferences": false, 12 | "EnableAttributeReordering": true, 13 | "AttributeOrderingRuleGroups": [ 14 | "x:Class", 15 | "xmlns, xmlns:x", 16 | "xmlns:*", 17 | "x:Key, Key, x:Name, Name, x:Uid, Uid, Title", 18 | "TargetType, BasedOn", 19 | "Grid.Row, Grid.RowSpan, Grid.Column, Grid.ColumnSpan, Canvas.Left, Canvas.Top, Canvas.Right, Canvas.Bottom", 20 | "Width, Height, MinWidth, MinHeight, MaxWidth, MaxHeight", 21 | "Margin, Padding, HorizontalAlignment, VerticalAlignment, HorizontalContentAlignment, VerticalContentAlignment, Panel.ZIndex", 22 | "*:*, *", 23 | "PageSource, PageIndex, Offset, Color, TargetName, Property, Value, StartPoint, EndPoint", 24 | "*:Freeze, mc:Ignorable, d:IsDataSource, d:LayoutOverrides, d:IsStaticText", 25 | "Storyboard.*, From, To, Duration" 26 | ], 27 | "FirstLineAttributes": "", 28 | "OrderAttributesByName": true, 29 | "PutEndingBracketOnNewLine": false, 30 | "RemoveEndingTagOfEmptyElement": true, 31 | "SpaceBeforeClosingSlash": true, 32 | "RootElementLineBreakRule": 1, 33 | "ReorderVSM": 2, 34 | "ReorderGridChildren": false, 35 | "ReorderCanvasChildren": false, 36 | "ReorderSetters": 3, 37 | "FormatMarkupExtension": true, 38 | "NoNewLineMarkupExtensions": "x:Bind, Binding, TemplateBinding, x:Static, DynamicResource, ComponentResourceKey, iconPacks:Modern, iconPacks:Material", 39 | "ThicknessSeparator": 1, 40 | "ThicknessAttributes": "Margin, Padding, BorderThickness, ThumbnailClipMargin", 41 | "FormatOnSave": false, 42 | "CommentPadding": 2, 43 | } -------------------------------------------------------------------------------- /src/Showcase/Models/GroupedDropHandler.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Linq; 3 | using GongSolutions.Wpf.DragDrop; 4 | 5 | namespace Showcase.WPF.DragDrop.Models 6 | { 7 | /// 8 | /// Custom drop handler which is used for the grouping example. 9 | /// 10 | public class GroupedDropHandler : IDropTarget 11 | { 12 | #if !NETCOREAPP3_1_OR_GREATER 13 | /// 14 | public void DragEnter(IDropInfo dropInfo) 15 | { 16 | // nothing here 17 | } 18 | 19 | /// 20 | public void DropHint(IDropHintInfo dropHintInfo) 21 | { 22 | // nothing here 23 | } 24 | #endif 25 | 26 | /// 27 | public void DragOver(IDropInfo dropInfo) 28 | { 29 | // Call default DragOver method, cause most stuff should work by default 30 | GongSolutions.Wpf.DragDrop.DragDrop.DefaultDropHandler.DragOver(dropInfo); 31 | if (dropInfo.TargetGroup == null) 32 | { 33 | dropInfo.Effects = System.Windows.DragDropEffects.None; 34 | } 35 | } 36 | 37 | #if !NETCOREAPP3_1_OR_GREATER 38 | /// 39 | public void DragLeave(IDropInfo dropInfo) 40 | { 41 | // nothing here 42 | } 43 | #endif 44 | 45 | /// 46 | public void Drop(IDropInfo dropInfo) 47 | { 48 | // The default drop handler don't know how to set an item's group. You need to explicitly set the group on the dropped item like this. 49 | GongSolutions.Wpf.DragDrop.DragDrop.DefaultDropHandler.Drop(dropInfo); 50 | 51 | // Now extract the dragged group items and set the new group (target) 52 | var data = DefaultDropHandler.ExtractData(dropInfo.Data).OfType().ToList(); 53 | foreach (var groupedItem in data) 54 | { 55 | groupedItem.Group = dropInfo.TargetGroup.Name.ToString(); 56 | } 57 | 58 | // Changing group data at runtime isn't handled well: force a refresh on the collection view. 59 | if (dropInfo.TargetCollection is ICollectionView) 60 | { 61 | ((ICollectionView)dropInfo.TargetCollection).Refresh(); 62 | } 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /src/GongSolutions.WPF.DragDrop/IDropTarget.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | 3 | namespace GongSolutions.Wpf.DragDrop 4 | { 5 | /// 6 | /// Interface implemented by Drop Handlers. 7 | /// 8 | public interface IDropTarget 9 | { 10 | /// 11 | /// Notifies the drop handler when a drag is initiated to display hint about potential drop targets. 12 | /// 13 | /// Object which contains several drop information. 14 | #if NETCOREAPP3_1_OR_GREATER 15 | void DropHint(IDropHintInfo dropHintInfo) 16 | { 17 | // nothing here 18 | } 19 | #else 20 | void DropHint(IDropHintInfo dropHintInfo); 21 | #endif 22 | 23 | /// 24 | /// Notifies the drop handler when dragging operation enters a potential drop target. 25 | /// 26 | /// Object which contains several drop information. 27 | #if NETCOREAPP3_1_OR_GREATER 28 | void DragEnter(IDropInfo dropInfo) 29 | { 30 | // nothing here 31 | } 32 | #else 33 | void DragEnter(IDropInfo dropInfo); 34 | #endif 35 | 36 | /// 37 | /// Notifies the drop handler about the current drag operation state. 38 | /// 39 | /// Object which contains several drop information. 40 | /// 41 | /// To allow a drop at the current drag position, the property on 42 | /// should be set to a value other than 43 | /// and should be set to a non-null value. 44 | /// 45 | void DragOver(IDropInfo dropInfo); 46 | 47 | /// 48 | /// Notifies the drop handler when dragging operation leaves a potential drop target. 49 | /// 50 | /// Object which contains several drop information. 51 | #if NETCOREAPP3_1_OR_GREATER 52 | void DragLeave(IDropInfo dropInfo) 53 | { 54 | // nothing here 55 | } 56 | #else 57 | void DragLeave(IDropInfo dropInfo); 58 | #endif 59 | 60 | /// 61 | /// Performs a drop on the target. 62 | /// 63 | /// Object which contains several drop information. 64 | void Drop(IDropInfo dropInfo); 65 | } 66 | } -------------------------------------------------------------------------------- /src/GongSolutions.WPF.DragDrop/Utilities/MouseHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Runtime.InteropServices; 4 | 5 | namespace GongSolutions.Wpf.DragDrop.Utilities 6 | { 7 | // Taken from Fluent Drag&Drop https://github.com/punker76/FluentDragDrop 8 | internal static class MouseHelper 9 | { 10 | private static System.Windows.Threading.DispatcherTimer _timer; 11 | 12 | internal static void HookMouseMove(IDragSource dragHandler, Action mouseMoveHandler) 13 | { 14 | _timer = new System.Windows.Threading.DispatcherTimer(System.Windows.Threading.DispatcherPriority.Input); 15 | _timer.Tick += (_, _) => 16 | { 17 | try 18 | { 19 | if (TryGetCursorPos(out var lpPoint)) 20 | { 21 | mouseMoveHandler?.Invoke(new System.Windows.Point(lpPoint.x, lpPoint.y)); 22 | } 23 | } 24 | catch (Exception ex) 25 | { 26 | if (!dragHandler.TryCatchOccurredException(ex)) 27 | { 28 | throw; 29 | } 30 | } 31 | }; 32 | _timer.Interval = new TimeSpan(1); 33 | _timer.Start(); 34 | } 35 | 36 | internal static void UnHook() 37 | { 38 | _timer.Stop(); 39 | } 40 | 41 | [StructLayout(LayoutKind.Sequential)] 42 | private struct POINT 43 | { 44 | public int x; 45 | public int y; 46 | } 47 | 48 | [DllImport("user32.dll", EntryPoint = "GetCursorPos", ExactSpelling = true, CharSet = CharSet.Auto, SetLastError = true)] 49 | [return: MarshalAs(UnmanagedType.Bool)] 50 | private static extern bool _GetCursorPos(out POINT lpPoint); 51 | 52 | private static bool TryGetCursorPos(out POINT pt) 53 | { 54 | var returnValue = _GetCursorPos(out pt); 55 | // Sometimes Win32 will fail this call, such as if you are 56 | // not running in the interactive desktop. For example, 57 | // a secure screen saver may be running. 58 | if (!returnValue) 59 | { 60 | Trace.WriteLine("GetCursorPos failed!"); 61 | pt.x = 0; 62 | pt.y = 0; 63 | } 64 | 65 | return returnValue; 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /src/GongSolutions.WPF.DragDrop/DropTargetAdorner.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows; 3 | using System.Windows.Documents; 4 | using System.Windows.Media; 5 | using JetBrains.Annotations; 6 | 7 | namespace GongSolutions.Wpf.DragDrop 8 | { 9 | /// 10 | /// Base class for drop target Adorner. 11 | /// 12 | public abstract class DropTargetAdorner : Adorner 13 | { 14 | [CanBeNull] 15 | private readonly AdornerLayer adornerLayer; 16 | 17 | /// 18 | /// Gets or Sets the pen which can be used for the render process. 19 | /// 20 | public Pen Pen { get; set; } = new Pen(Brushes.Gray, 2); 21 | 22 | public IDropInfo DropInfo { get; set; } 23 | 24 | public DropTargetAdorner(UIElement adornedElement, IDropInfo dropInfo) 25 | : base(adornedElement) 26 | { 27 | this.DropInfo = dropInfo; 28 | this.IsHitTestVisible = false; 29 | this.AllowDrop = false; 30 | this.SnapsToDevicePixels = true; 31 | this.adornerLayer = AdornerLayer.GetAdornerLayer(adornedElement); 32 | // can be null but should normally not be null 33 | this.adornerLayer?.Add(this); 34 | } 35 | 36 | /// 37 | /// Detach the adorner from its adorner layer. 38 | /// 39 | public void Detach() 40 | { 41 | if (this.adornerLayer is null) 42 | { 43 | return; 44 | } 45 | 46 | if (!this.adornerLayer.Dispatcher.CheckAccess()) 47 | { 48 | this.adornerLayer.Dispatcher.Invoke(this.Detach); 49 | return; 50 | } 51 | 52 | this.adornerLayer.Remove(this); 53 | } 54 | 55 | internal static DropTargetAdorner Create(Type type, UIElement adornedElement, IDropInfo dropInfo) 56 | { 57 | if (!typeof(DropTargetAdorner).IsAssignableFrom(type)) 58 | { 59 | throw new InvalidOperationException("The requested adorner class does not derive from DropTargetAdorner."); 60 | } 61 | 62 | var ctor = type.GetConstructor(new[] { typeof(UIElement), typeof(IDropInfo) }); 63 | if (ctor is null && dropInfo is DropInfo) 64 | { 65 | ctor = type.GetConstructor(new[] { typeof(UIElement), typeof(DropInfo) }); 66 | } 67 | 68 | return ctor?.Invoke(new object[] { adornedElement, dropInfo }) as DropTargetAdorner; 69 | } 70 | } 71 | } -------------------------------------------------------------------------------- /src/GongSolutions.WPF.DragDrop/IDragSource.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows; 3 | 4 | namespace GongSolutions.Wpf.DragDrop 5 | { 6 | /// 7 | /// Interface implemented by Drag Handlers. 8 | /// 9 | public interface IDragSource 10 | { 11 | /// 12 | /// Queries whether a drag can be started. 13 | /// 14 | /// Object which contains several drag information. 15 | /// 16 | /// To allow a drag to be started, the property on 17 | /// should be set to a value other than . 18 | /// 19 | void StartDrag(IDragInfo dragInfo); 20 | 21 | /// 22 | /// Determines whether this instance [can start drag] the specified drag information. 23 | /// With this action it's possible to check if the drag and drop operation is allowed to start 24 | /// e.g. check for a UIElement inside a list view item, that should not start a drag and drop operation 25 | /// 26 | /// Object which contains several drag information. 27 | /// True if the drag and drop operation is allowed. 28 | bool CanStartDrag(IDragInfo dragInfo); 29 | 30 | /// 31 | /// Notifies the drag handler that a drop has occurred. 32 | /// 33 | /// Object which contains several drop information. 34 | void Dropped(IDropInfo dropInfo); 35 | 36 | /// 37 | /// Notifies the drag handler that a drag and drop operation has finished. 38 | /// 39 | /// The operation result. 40 | /// Object which contains several drag information. 41 | void DragDropOperationFinished(DragDropEffects operationResult, IDragInfo dragInfo); 42 | 43 | /// 44 | /// Notifies the drag handler that a drag has been aborted. 45 | /// 46 | void DragCancelled(); 47 | 48 | /// 49 | /// Notifies that an exception has occurred upon dragging. 50 | /// 51 | /// The exception that occurred. 52 | /// 53 | /// Boolean indicating whether the exception is handled in the drag handler. 54 | /// False will rethrow the exception. 55 | /// 56 | bool TryCatchOccurredException(Exception exception); 57 | } 58 | } -------------------------------------------------------------------------------- /src/GongSolutions.WPF.DragDrop/DropTargetHighlightAdorner.cs: -------------------------------------------------------------------------------- 1 | using GongSolutions.Wpf.DragDrop.Utilities; 2 | using System.Windows; 3 | using System.Windows.Controls; 4 | using System.Windows.Media; 5 | 6 | namespace GongSolutions.Wpf.DragDrop 7 | { 8 | public class DropTargetHighlightAdorner : DropTargetAdorner 9 | { 10 | public DropTargetHighlightAdorner(UIElement adornedElement, IDropInfo dropInfo) 11 | : base(adornedElement, dropInfo) 12 | { 13 | } 14 | 15 | /// 16 | /// The background brush for the highlight rectangle for TreeViewItem. This can be overridden through 17 | /// . The default value is . 18 | /// 19 | public Brush Background { get; set; } = Brushes.Transparent; 20 | 21 | /// 22 | /// When overridden in a derived class, participates in rendering operations that are directed by the layout system. 23 | /// The rendering instructions for this element are not used directly when this method is invoked, and are instead preserved for 24 | /// later asynchronous use by layout and drawing. 25 | /// 26 | /// The drawing instructions for a specific element. This context is provided to the layout system. 27 | protected override void OnRender(DrawingContext drawingContext) 28 | { 29 | var dropInfo = this.DropInfo; 30 | var visualTargetItem = dropInfo.VisualTargetItem; 31 | if (visualTargetItem != null) 32 | { 33 | var rect = Rect.Empty; 34 | 35 | var tvItem = visualTargetItem as TreeViewItem; 36 | if (tvItem != null && VisualTreeHelper.GetChildrenCount(tvItem) > 0) 37 | { 38 | var descendant = VisualTreeExtensions.GetVisibleDescendantBounds(tvItem); 39 | var translatePoint = tvItem.TranslatePoint(new Point(), this.AdornedElement); 40 | var itemRect = new Rect(translatePoint, tvItem.RenderSize); 41 | descendant.Union(itemRect); 42 | translatePoint.Offset(1, 0); 43 | rect = new Rect(translatePoint, new Size(descendant.Width - translatePoint.X - 1, tvItem.ActualHeight)); 44 | } 45 | 46 | if (rect.IsEmpty) 47 | { 48 | var bounds = VisualTreeExtensions.GetVisibleDescendantBounds(visualTargetItem); 49 | var location = visualTargetItem.TranslatePoint(bounds.Location, this.AdornedElement); 50 | rect = new Rect(location, bounds.Size); 51 | } 52 | 53 | drawingContext.DrawRoundedRectangle(this.Background, this.Pen, rect, 2, 2); 54 | } 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /src/Showcase/Models/SerializableDragHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Windows; 5 | using GongSolutions.Wpf.DragDrop; 6 | using GongSolutions.Wpf.DragDrop.Utilities; 7 | 8 | namespace Showcase.WPF.DragDrop.Models 9 | { 10 | [Serializable] 11 | public class SerializableWrapper 12 | { 13 | public IEnumerable Items { get; set; } 14 | 15 | public DragDropKeyStates DragDropCopyKeyState { get; set; } 16 | } 17 | 18 | public class SerializableDragHandler : IDragSource 19 | { 20 | private bool alreadyDropped = false; 21 | 22 | /// 23 | public void StartDrag(IDragInfo dragInfo) 24 | { 25 | this.alreadyDropped = false; 26 | var items = dragInfo.SourceItems.OfType().ToList(); 27 | var wrapper = new SerializableWrapper() 28 | { 29 | Items = items, 30 | DragDropCopyKeyState = DragDropKeyStates.ControlKey //dragInfo.DragDropCopyKeyState 31 | }; 32 | dragInfo.Data = wrapper; 33 | dragInfo.DataFormat = DataFormats.GetDataFormat(DataFormats.Serializable); 34 | dragInfo.Effects = dragInfo.Data != null ? DragDropEffects.Copy | DragDropEffects.Move : DragDropEffects.None; 35 | } 36 | 37 | /// 38 | public bool CanStartDrag(IDragInfo dragInfo) 39 | { 40 | return true; 41 | } 42 | 43 | /// 44 | public void Dropped(IDropInfo dropInfo) 45 | { 46 | this.alreadyDropped = true; 47 | } 48 | 49 | /// 50 | public void DragDropOperationFinished(DragDropEffects operationResult, IDragInfo dragInfo) 51 | { 52 | if (this.alreadyDropped || dragInfo == null) 53 | { 54 | return; 55 | } 56 | 57 | // the drag operation has finished on another app 58 | if (operationResult != DragDropEffects.None) 59 | { 60 | if (operationResult.HasFlag(DragDropEffects.Move)) 61 | { 62 | var sourceList = dragInfo.SourceCollection.TryGetList(); 63 | var items = dragInfo.SourceItems.OfType().ToList(); 64 | if (sourceList != null) 65 | { 66 | foreach (var o in items) 67 | { 68 | sourceList.Remove(o); 69 | } 70 | } 71 | 72 | this.alreadyDropped = true; 73 | } 74 | } 75 | } 76 | 77 | /// 78 | public void DragCancelled() 79 | { 80 | } 81 | 82 | /// 83 | public bool TryCatchOccurredException(Exception exception) 84 | { 85 | return false; 86 | } 87 | } 88 | } -------------------------------------------------------------------------------- /src/Showcase/Views/SettingsView.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Controls; 3 | 4 | namespace Showcase.WPF.DragDrop.Views 5 | { 6 | using System.Windows.Input; 7 | 8 | /// 9 | /// Interaction logic for SettingsView.xaml 10 | /// 11 | public partial class SettingsView : UserControl 12 | { 13 | public SettingsView() 14 | { 15 | this.InitializeComponent(); 16 | } 17 | 18 | public static readonly DependencyProperty CaptionProperty 19 | = DependencyProperty.Register(nameof(Caption), 20 | typeof(string), 21 | typeof(SettingsView), 22 | new PropertyMetadata(default(string))); 23 | 24 | public string Caption 25 | { 26 | get => (string)this.GetValue(CaptionProperty); 27 | set => this.SetValue(CaptionProperty, value); 28 | } 29 | 30 | public static readonly DependencyProperty ShowCopyKeyStateProperty 31 | = DependencyProperty.Register(nameof(ShowCopyKeyState), 32 | typeof(bool), 33 | typeof(SettingsView), 34 | new PropertyMetadata(default(bool))); 35 | 36 | public bool ShowCopyKeyState 37 | { 38 | get => (bool)this.GetValue(ShowCopyKeyStateProperty); 39 | set => this.SetValue(ShowCopyKeyStateProperty, value); 40 | } 41 | 42 | public static readonly DependencyProperty FilterCollectionCommandProperty 43 | = DependencyProperty.Register(nameof(FilterCollectionCommand), 44 | typeof(ICommand), 45 | typeof(SettingsView), 46 | new PropertyMetadata(default(ICommand), (o, args) => ((SettingsView)o).FilterCollectionCommandShown = args.NewValue != null)); 47 | 48 | public ICommand FilterCollectionCommand 49 | { 50 | get => (ICommand)this.GetValue(FilterCollectionCommandProperty); 51 | set => this.SetValue(FilterCollectionCommandProperty, value); 52 | } 53 | 54 | private static readonly DependencyPropertyKey FilterCollectionCommandShownPropertyKey 55 | = DependencyProperty.RegisterReadOnly(nameof(FilterCollectionCommandShown), 56 | typeof(bool), 57 | typeof(SettingsView), 58 | new PropertyMetadata(default(bool))); 59 | 60 | public static readonly DependencyProperty FilterCollectionCommandShownProperty = FilterCollectionCommandShownPropertyKey.DependencyProperty; 61 | 62 | public bool FilterCollectionCommandShown 63 | { 64 | get => (bool)this.GetValue(FilterCollectionCommandShownProperty); 65 | protected set => this.SetValue(FilterCollectionCommandShownPropertyKey, value); 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /src/Showcase/app.manifest: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | true/PM 38 | 39 | 40 | PerMonitorV2, PerMonitor 41 | 42 | 43 | 44 | 45 | 46 | 47 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /src/Showcase/Models/TreeNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.ObjectModel; 3 | using System.ComponentModel; 4 | using System.Runtime.CompilerServices; 5 | using JetBrains.Annotations; 6 | using MahApps.Metro.IconPacks; 7 | 8 | namespace Showcase.WPF.DragDrop.Models 9 | { 10 | public class TreeNode : INotifyPropertyChanged, ICloneable 11 | { 12 | private PackIconMaterialKind _icon; 13 | private string _caption; 14 | private ObservableCollection _children; 15 | private bool _isCloned; 16 | private bool _isExpanded; 17 | 18 | public TreeNode(string caption) 19 | { 20 | this.Caption = caption; 21 | this.Children = new ObservableCollection(); 22 | } 23 | 24 | public PackIconMaterialKind Icon 25 | { 26 | get => this._icon; 27 | set 28 | { 29 | if (value == this._icon) return; 30 | this._icon = value; 31 | this.OnPropertyChanged(); 32 | } 33 | } 34 | 35 | public string Caption 36 | { 37 | get => this._caption; 38 | set 39 | { 40 | if (value == this._caption) return; 41 | this._caption = value; 42 | this.OnPropertyChanged(); 43 | } 44 | } 45 | 46 | public ObservableCollection Children 47 | { 48 | get => this._children; 49 | set 50 | { 51 | if (Equals(value, this._children)) return; 52 | this._children = value; 53 | this.OnPropertyChanged(); 54 | } 55 | } 56 | 57 | public bool IsCloned 58 | { 59 | get => this._isCloned; 60 | set 61 | { 62 | if (value == this._isCloned) return; 63 | this._isCloned = value; 64 | this.OnPropertyChanged(); 65 | } 66 | } 67 | 68 | public bool IsExpanded 69 | { 70 | get => this._isExpanded; 71 | set 72 | { 73 | if (value == this._isExpanded) return; 74 | this._isExpanded = value; 75 | this.OnPropertyChanged(); 76 | } 77 | } 78 | 79 | public override string ToString() 80 | { 81 | return this.Caption; 82 | } 83 | 84 | public object Clone() 85 | { 86 | var treeNode = new TreeNode(this.Caption) { IsCloned = true }; 87 | foreach (var child in this.Children) 88 | { 89 | treeNode.Children.Add((TreeNode)child.Clone()); 90 | } 91 | return treeNode; 92 | } 93 | 94 | public event PropertyChangedEventHandler PropertyChanged; 95 | 96 | [NotifyPropertyChangedInvocator] 97 | protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) 98 | { 99 | this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 100 | } 101 | } 102 | } -------------------------------------------------------------------------------- /src/Showcase/Models/CustomDropHintHandler.cs: -------------------------------------------------------------------------------- 1 | namespace Showcase.WPF.DragDrop.Models; 2 | 3 | using System.Linq; 4 | using System.Windows; 5 | using GongSolutions.Wpf.DragDrop; 6 | 7 | public class CustomDropHintHandler : DefaultDropHandler 8 | { 9 | /// 10 | /// When false, will set red border and hint text to "Drop not allowed for this element" 11 | /// 12 | public bool IsDropAllowed { get; set; } = true; 13 | public bool BlockOdd { get; set; } 14 | 15 | /// 16 | /// Do not display active hint on mouse over. 17 | /// 18 | public bool IsActiveHintDisabled { get; set; } 19 | 20 | public override void DropHint(IDropHintInfo dropHintInfo) 21 | { 22 | if (!this.CanAccept(dropHintInfo.DragInfo)) 23 | { 24 | return; 25 | } 26 | 27 | if (!this.IsDropAllowed) 28 | { 29 | dropHintInfo.DropTargetHintAdorner = DropTargetAdorners.Hint; 30 | dropHintInfo.DropTargetHintState = DropHintState.Error; 31 | dropHintInfo.DropHintText = "Drop not allowed for this element"; 32 | } 33 | else 34 | { 35 | dropHintInfo.DropHintText = "Drop data here"; 36 | dropHintInfo.DropTargetHintAdorner = typeof(DropTargetHintAdorner); 37 | } 38 | } 39 | 40 | public override void DragOver(IDropInfo dropInfo) 41 | { 42 | if (!this.CanAccept(dropInfo.DragInfo)) 43 | { 44 | return; 45 | } 46 | 47 | if (!IsDropAllowed) 48 | { 49 | dropInfo.DropTargetHintAdorner = DropTargetAdorners.Hint; 50 | dropInfo.DropTargetHintState = DropHintState.Error; 51 | dropInfo.DropHintText = "Drop not allowed for this element"; 52 | return; 53 | } 54 | 55 | if (BlockOdd && dropInfo.DragInfo.SourceItem is ItemModel item && item.Index % 2 != 0) 56 | { 57 | dropInfo.DropTargetHintAdorner = DropTargetAdorners.Hint; 58 | dropInfo.DropTargetHintState = DropHintState.Error; 59 | dropInfo.DropHintText = "Only items with even index is allowed"; 60 | dropInfo.Effects = DragDropEffects.None; 61 | return; 62 | } 63 | 64 | var copyData = ShouldCopyData(dropInfo); 65 | 66 | dropInfo.Effects = copyData ? DragDropEffects.Copy : DragDropEffects.Move; 67 | dropInfo.DropTargetAdorner = DropTargetAdorners.Highlight; 68 | dropInfo.EffectText = "Send"; 69 | if(IsActiveHintDisabled) 70 | { 71 | // No drag over hint 72 | return; 73 | } 74 | 75 | dropInfo.DropTargetHintAdorner = DropTargetAdorners.Hint; 76 | dropInfo.DropHintText = $"Dropping {(dropInfo.DragInfo.SourceItem as ItemModel)?.Caption} on {(dropInfo.TargetItem as ItemModel)?.Caption}"; 77 | dropInfo.DropTargetHintState = DropHintState.Active; 78 | } 79 | 80 | 81 | private bool CanAccept(IDragInfo dragInfo) 82 | { 83 | if (dragInfo == null) 84 | { 85 | return false; 86 | } 87 | 88 | var items = ExtractData(dragInfo.Data) 89 | .OfType() 90 | .ToList(); 91 | return items.Count > 0; 92 | } 93 | } -------------------------------------------------------------------------------- /src/Showcase/Models/TextBoxCustomDropHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Windows; 4 | using System.Windows.Controls; 5 | using System.Windows.Media; 6 | using GongSolutions.Wpf.DragDrop; 7 | 8 | namespace Showcase.WPF.DragDrop.Models 9 | { 10 | public class TextBoxCustomDropHandler : IDropTarget 11 | { 12 | #if !NETCOREAPP3_1_OR_GREATER 13 | /// 14 | public void DragEnter(IDropInfo dropInfo) 15 | { 16 | // nothing here 17 | } 18 | 19 | /// 20 | public void DropHint(IDropHintInfo dropHintInfo) 21 | { 22 | // nothing here 23 | } 24 | #endif 25 | 26 | /// 27 | public void DragOver(IDropInfo dropInfo) 28 | { 29 | dropInfo.DropTargetAdorner = typeof(DropTargetHighlightAdorner); 30 | dropInfo.Effects = DragDropEffects.Move; 31 | } 32 | 33 | #if !NETCOREAPP3_1_OR_GREATER 34 | /// 35 | public void DragLeave(IDropInfo dropInfo) 36 | { 37 | // nothing here 38 | } 39 | #endif 40 | 41 | /// 42 | public void Drop(IDropInfo dropInfo) 43 | { 44 | var textBox = (TextBox)dropInfo.VisualTarget; 45 | 46 | if (dropInfo.Data is IDataObject dataObject) 47 | { 48 | if (dataObject.GetDataPresent(DataFormats.Text)) 49 | { 50 | textBox.Text = dataObject.GetData(DataFormats.Text) as string ?? string.Empty; 51 | } 52 | else if (dataObject.GetDataPresent(DataFormats.FileDrop)) 53 | { 54 | // Note that you can have more than one file. 55 | string[] files = (string[])dataObject.GetData(DataFormats.FileDrop); 56 | textBox.Text = string.Join(Environment.NewLine, files); 57 | } 58 | } 59 | else 60 | { 61 | var realData = DefaultDropHandler.ExtractData(dropInfo.Data); 62 | textBox.Text = string.Join(", ", realData.OfType().ToArray()); 63 | } 64 | } 65 | } 66 | 67 | public class DropTargetHighlightAdorner : DropTargetAdorner 68 | { 69 | private readonly Pen _pen; 70 | private readonly Brush _brush; 71 | 72 | public DropTargetHighlightAdorner(UIElement adornedElement, IDropInfo dropInfo) 73 | : base(adornedElement, dropInfo) 74 | { 75 | this._pen = new Pen(Brushes.Tomato, 2); 76 | this._pen.Freeze(); 77 | this._brush = new SolidColorBrush(Colors.Coral) { Opacity = 0.2 }; 78 | this._brush.Freeze(); 79 | 80 | this.SetValue(SnapsToDevicePixelsProperty, true); 81 | } 82 | 83 | protected override void OnRender(DrawingContext drawingContext) 84 | { 85 | var visualTarget = this.DropInfo.VisualTarget; 86 | if (visualTarget != null) 87 | { 88 | var translatePoint = visualTarget.TranslatePoint(new Point(), this.AdornedElement); 89 | translatePoint.Offset(1, 1); 90 | var bounds = new Rect(translatePoint, 91 | new Size(visualTarget.RenderSize.Width - 2, visualTarget.RenderSize.Height - 2)); 92 | drawingContext.DrawRectangle(this._brush, this._pen, bounds); 93 | } 94 | } 95 | } 96 | } -------------------------------------------------------------------------------- /src/Showcase/Views/DataGridSamples.xaml: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 |