Drag and drop from custom dockpane on map or table of content (instead of on dockpane)

420
3
12-06-2023 12:59 AM
nadja_swiss_parks
Occasional Contributor II

I know there are already several posts, but none quite what I need. I've got a custom dockpane which lists data from three different sources in three different treeviews. let's start with the vectors. 

I can select my items and drop them on my vector_treeview which adds them with my custom method to my map. 

at the start I have

 vector_gdbTreeView.PreviewMouseLeftButtonDown += vector_DirectoryTreeView_PreviewMouseLeftButtonDown;
 vector_gdbTreeView.PreviewMouseMove += vector_DirectoryTreeView_PreviewMouseMove;
 vector_gdbTreeView.AllowDrop = true;
 vector_gdbTreeView.Drop += vector_DirectoryTreeView_Drop;

and then the methods

private async Task AddVectorToMapMethod_string(string data_path)
{
...
}

private System.Windows.Point startPoint;

private void vector_DirectoryTreeView_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    startPoint = e.GetPosition(null);
}

private void vector_DirectoryTreeView_PreviewMouseMove(object sender, MouseEventArgs e)
{
    if (e.LeftButton == MouseButtonState.Pressed)
    {
        System.Windows.Point mousePos = e.GetPosition(null);
        Vector diff = startPoint - mousePos;

        if (Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance ||
            Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance)
        {
           System.Windows.MessageBox.Show(string.Join(Environment.NewLine, vector_selectedFileUrls), "Items");

            // only handle one selected url
            
                DataObject dragData = new DataObject("MyFormat", vector_selectedFileUrls.ToList()[0].ToString());
                DragDrop.DoDragDrop(vector_gdbTreeView, dragData, DragDropEffects.Move);
                          
        }
    }
}

private async void vector_DirectoryTreeView_Drop(object sender, DragEventArgs e)
{
    if (e.Data.GetDataPresent("MyFormat"))
    {
        var droppedData = e.Data.GetData("MyFormat");

        if (droppedData != null)
        {
            await QueuedTask.Run(async () =>
            {
                
                // Perform your drop operation here based on droppedData
                await AddVectorToMapMethod_string(droppedData.ToString());
                
            });
        }
    }
}

However I cannot figure out how to allow dropping it also in the table of content or on the map directly or on the entire surface of ArcGIS Pro. I thought I just need to set AllowDrop on those elements, but I cannot figure out how to reference these elements so that it allows AllowDrop... Can anyone please help me? thank you in advance 🙂

0 Kudos
3 Replies
GKmieliauskas
Esri Regular Contributor

Hi, 

To drop on content or map your data in clipboard must be in format: List<ClipboardItem>. Look at the DragAndDrop sample

Map or TOC doesn't understand custom data formats. 

So if you want to drag and drop between your controls and map you need to use ArcGIS Pro format.

0 Kudos
nadja_swiss_parks
Occasional Contributor II

Thank you @GKmieliauskas - I saw that sample, but honestly I don't understand it (hardly any comments in the code and two or three similar drag&drop functions in the same example is not exactly beginnerfriendly...).

Anyway, can you tell me which part there is relevant for me? Since you pointed out that I need to use List<ClipboardItem> and the example seems to add feature classes to the map, I assume it's this

private async Task<ObservableCollection<GDBBaseItem>> GetGDBItemsAsync()
		{
			var gdbItems = await QueuedTask.Run<ObservableCollection<GDBBaseItem>>(() =>
			{
				List<GDBBaseItem> lstGDBBaseItems = new List<GDBBaseItem>();
				//Database becomes the root node
				var path = Name;
				var root = new DatabaseGDBItem { DBName = System.IO.Path.GetFileName(Name), Name = path, Path = path };
				lstGDBBaseItems.Add(root);
				// use the geodatabase to get all layers
				var fGdbPath = new FileGeodatabaseConnectionPath(new Uri(Name, UriKind.Absolute));
				using (var gdb = new Geodatabase(fGdbPath))
				{
					IReadOnlyList<Definition> fcList = gdb.GetDefinitions<FeatureClassDefinition>();
					//Feature class
					foreach (FeatureClassDefinition fcDef in fcList)
					{
						var fc = gdb.OpenDataset<FeatureClass>(fcDef.GetName());
						var fd = fc.GetFeatureDataset();
						var fc_path = (fd == null) ? path : path + @"\" + fd.GetName();
						fc.Dispose();
						fd?.Dispose();
						switch (fcDef.GetShapeType())
						{
							case GeometryType.Point:
								var pointfcItem = new PointFCGDBItem { Name = fcDef.GetName(), Path = fc_path };
								root.Children.Add(pointfcItem);
								break;
							case GeometryType.Polyline:
								var linefcItem = new LineFCGDBItem { Name = fcDef.GetName(), Path = fc_path };
								root.Children.Add(linefcItem);
								break;
							case GeometryType.Polygon:
								var polyfcItem = new PolygonFCGDBItem { Name = fcDef.GetName(), Path = fc_path };
								root.Children.Add(polyfcItem);
								break;
						}
					}
				}
				root.IsExpanded = true;

				return new ObservableCollection<GDBBaseItem>(lstGDBBaseItems);
			});

			return gdbItems;
		}

		public void StartDrag(DragInfo dragInfo)
		{
			var sourceItem = dragInfo.SourceItem;
			if (sourceItem == null)
				return;
			var gdbItem = dragInfo.SourceItem as GDBBaseItem;
			if (gdbItem == null)
				return;

			if (gdbItem is DatabaseGDBItem)
				return;//no dragging of the gdb

			List<ClipboardItem> clip_items = new List<ClipboardItem>();
			clip_items.Add(new ClipboardItem()
			{
				ItemInfoValue = gdbItem.GetItemInfoValue()
			});
			dragInfo.Data = clip_items;
			dragInfo.Effects = DragDropEffects.Copy;
		}

 

0 Kudos
GKmieliauskas
Esri Regular Contributor

You must fill ClipboardItem from your own data like in method from DragAndDrop sample:

		public virtual ItemInfoValue GetItemInfoValue()
		{
			var uri = _path + @"\" + _name;
			var gdb_item = ItemFactory.Instance.Create(uri);
			if (gdb_item == null)
			{
				MessageBox.Show($@"Unable to locate: {uri} - Feature datasets are not supported.");
			}
			return new ItemInfoValue()
			{
				name = gdb_item?.Name,
				title = gdb_item?.Name,
				catalogPath = gdb_item?.Path,
				type = gdb_item?.Type,
				typeID = gdb_item?.TypeID,
				isContainer = "false"
			};
		}

Your dockpane must implement IDragSource interface (like in sample)

 

0 Kudos